Say I have the following function:
def sub1(a,b,foo="bar"):
print(a b)
print(foo)
def main(*args,**kwargs):
a,b = args
sub1(a,b,**kwargs)
I can do
main(2,3) #5, bar
main(2,3,foo="baz") #5, baz
which works fine.
But say I have parse an additioanl keyword-argument like
main(2,3,qux="baz") #TypeError: sub1() got an unexpected keyword argument 'qux'
Why would we do this? Say I have an additional function which shares some of the arguments with sub1
but also have some arguments that are different
def sub2(foo,qux="fred"):
print(foo)
print(f"Hello {qux}")
then instead of having to do
def main(*args,**sub1kwargs,**sub2kwargs):
sub1(**sub1kwargs)
sub2(**sub2kwargs)
we could just parse the same kwargs
around and the function just takes what it needs:
def main(*args,**kwargs):
sub1(**kwargs)
sub2(**kwargs)
Of course we could just loop over the parameter-list before parsing the parameters to sub1
, (or use foo = kwargs.get("foo","bar)
in sub1
) but I want to know, if we can avoid doing so and have only one kwargs
?
CodePudding user response:
"Explicit is better than implicit."
There is nothing really to be gained from passing anonymous kwargs
around. Functions should really name their keyword arguments whenever possible. And callers such as your main
do not improve in quality or readability by saving the odd byte of code. Process/filter the kwargs where needed. Either
def main(*args, foo="bar", qux="baz"):
sub1(*args, foo=foo)
sub2(qux=qux)
or
def main(*args, **kwargs):
sub1(*args, foo=kwargs.get("foo"))
sub2(qux=kwargs.get("qux"))
will do the job and be easily understood.
Of course, you can define a function like (do NOT):
def sub1(a, b, **kwargs):
print(a b)
print(kwargs.get("foo", "bar"))
This will allow callers to pass random kwargs that will be ignored, but it makes it much harder for the caller to find out what kwargs are really needed by this function.
CodePudding user response:
You can do it, just add kwargs to sub1 and it will auto-parse any named arguments you provided, and the rest will be put into kwargs:
def sub1(a, b, foo="bar", **kwargs):
That way you can still call sub1 with or without foo, but you can also call it with or without other arguments without causing an error.
main(1, 2, foo="hello")
> 1, 2, "hello"
main(1, 2, qux="hello")
> 1, 2, "bar"