Home > Software engineering >  Use kwargs in a function when it contains arguments not-used by the function
Use kwargs in a function when it contains arguments not-used by the function

Time:10-19

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"
  • Related