Ondřej Janča
Ondřej Janča

Reputation: 107

How do I pass a default parameter to a sub-function in a Pythonic way?

I am trying to solve this issue with passing default parameters.

I have functions creating plots with matplotlib. These functions accept parameters and some of those have default values:

def radar_with_CI(values, categories, group=0):
    ...

def multi_radar_with_CI(
    values,
    categories,
    fname: str,
    series_names="Series",
    pth="t:/Projects/dev/Plotter/"
):
    ...

def overlay_radar_with_CI(
    values,
    categories,
    fname: str,
    series_names="Series",
    pth="t:/Projects/dev/Plotter/"
):
    ...

Then there is a master function, that aggregates parameters and runs different functions based on 'mode'.

def radar(
    values,
    categories,
    fname,
    series_names="Series",
    pth="",
    mode="all",
    group=None
):
    if mode == "single":
        radar_with_CI(values, categories, group=group)

    if mode == "one-by-one" or mode == "all":
        multi_radar_with_CI(
            values,
            categories,
            series_names=series_names,
            fname=fname,
            pth=pth
        )

    if mode == "overlay" or mode == "all":
        overlay_radar_with_CI(
            values,
            categories,
            series_names=series_names,
            fname=fname,
            pth=pth
        )

Thing is, I need a default parameter for e.g. series_names, but I need this default parameter both in the master function and in the plotting functions themselves to be able to call them both through master function and separately.

In the code above my current solution is implemented: I made the parameter default in both the master and plotting functions.

Is this a correct solution? Or is it bad practice to stack default parameters on themselves (in other words to send a parameter with the same value as is the default one)? Is this a place for using args or kwargs?

Upvotes: -1

Views: 556

Answers (2)

jemsot
jemsot

Reputation: 11

I would make a Master class like so:

class Master:
    def __init__(self,mode,firstName='Tom',lastName='Smith'):
        self.firstName = firstName
        self.lastName = lastName
        self.mode = mode

        if self.mode == 'ModeA':
            self.functionOne()

        if self.mode == 'ModeB':
            self.functionTwo()

    def functionOne(self):
        print(self.firstName + ' ' + self.lastName)

    def functionTwo(self):
        print(self.lastName + ', ' + self.firstName)

a = Master('ModeA',lastName='Porter')
a = Master('ModeB',lastName='Porter')
a = Master('ModeB',firstName='Jeff',lastName='Charles')    

Output:

Tom Porter
Porter, Tom
Charles, Jeff

Upvotes: 1

Jonas Blatt
Jonas Blatt

Reputation: 64

Repeating yourself is always a bad idea (defining the default values multiple times).

I suggest defining the additional parameters as kwargs and unpack them in the function call:

def radar(values, categories, *, mode="all", **kwargs):
    if mode == "single":
        radar_with_CI(values, categories, **kwargs)

    if mode == "one-by-one" or mode == "all":
        multi_radar_with_CI(values, categories, **kwargs)

    if mode == "overlay" or mode == "all":
        overlay_radar_with_CI(values, categories, **kwargs)

So you can call your function radar, define one parameter (fname), and use the default values from the original function for the other parameters.

radar([1, 2, 3], ['A', 'B', 'C'], mode='overlay', fname='test')

Note that you will receive a TypeError if you pass a keyword argument not defined by the called function.

Upvotes: 1

Related Questions