I have a bunch of function what call each other which have a few optional parameters:
def f0(..., p1=3, p2=5):
...
def f1(..., p1=3, p2=5, p3=8, p4=13):
...
f0(..., p1=p1, p2=p2)
...
def f2(..., p1=3, p2=5, p3=8, p4=13, p5=21, p6=123):
...
f1(..., p1=p1, p2=p2, p3=p3, p4=p4)
...
def f3(..., p1=3, p2=5, p3=8, p4=13, p5=21, p6=123, ...):
...
f2(..., p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6)
...
Obviously, I don’t want to keep repeating those default values (123, 21, 13 &c)
all the time. It would also be nice to be able to pass None explicitly to
mean "use the appropriate default".
The obvious way to deal with this is something like
p1_default=3
p2_default=5
def f0(..., p1=None, p2=None):
p1 = p1 if p1 is not None else p1_default
p2 = p2 if p2 is not None else p2_default
...
p3_default=12
p4_default=15
def f1(..., p1=None, p2=None, p3=None, p4=None):
p3 = p3 if p3 is not None else p3_default
p4 = p4 if p4 is not None else p4_default
...
f0(..., p1=p1, p2=p2)
...
but this looks ugly and repetitive.
What is the "pythonic" way?
>Solution :
I would recommended using keyword arguments instead of positional arguments.
def f0(..., *, p1=3, p2=5):
...
def f1(..., *, p3=8, p4=13, **kwargs):
...
f0(..., **kwargs)
...
def f2(..., *, p5=21, p6=123, **kwargs):
...
f1(..., **kwargs)
...
def f3(..., **kwargs):
...
f2(..., **kwargs)
When you need to supply non-default values, you need to do a small amount of extra typing, but given the number of parameters you seem to have, this will probably be simpler than trying to remember the order in which argunents need to be provided. For example:
# p2 is still 5, p3 is still 8, p6 is still 123, etc
f3(p1=7, p5=16, p4=12)
Note, too, that 16 is assigned directly to p5 in the call to f2, rather than being collected in its kwargs, so it won’t be passed down to f1.