Python trying to place keyword arguments after *args

user2221323 picture user2221323 · Mar 16, 2014 · Viewed 7.2k times · Source

I'm a bit confused about using *args.

I want to write a function that takes a variable number of arguments but can still use the advantage of defining a predefined value for a keyword argument.

But it's not possible to write a function like this:

def foo(*args, bar = "foo"):
    print bar, args

It's just possible to write it like this:

def foo2(bar = "foo", *args):
    print bar, args

But then I call foo2 and pass the first argument it overrides the default value for bar!.

foo2("somevalue")
somevalue ()

Is where a way of doing this better ??

I know I could write it like this:

def foo(*args, **kwargs):
    kwargs["bar"] = "foo"

but something like the first method definition (which yields a syntax error) is more intuitive from my point of view.

Answer

Chris Seymour picture Chris Seymour · Mar 16, 2014

You would use kwargs and do the assignment in the call not the definition:

def foo2(*args, **kwargs):     # kwargs takes our key/values arguments
    print args, kwargs

foo2(1, 2, 3, bar="foo")       # bar is assigned to in call when using kwargs 

Which gives:

(1, 2, 3) {'bar': 'foo'} 

You could use get to set foo as a default for bar like so:

def foo2(*args, **kwargs):
    kwargs["bar"] = kwargs.get("bar", "foo") # if bar is not set use foo as val
    print args, kwargs

foo2(1, 2, 3, bar="foo")
foo2(1, 2, 3, bar="notfoo")
foo2(1, 2, 3)

So that kwargs["bar"] is always foo unless explicitly changed:

(1, 2, 3) {'bar': 'foo'}
(1, 2, 3) {'bar': 'notboo'}
(1, 2, 3) {'bar': 'foo'}