I have the following code:
def foo(func, *args, named_arg = None):
return func(*args)
returning a SyntaxError
:
File "tester3.py", line 3
def foo(func, *args, named_arg = None):
^
Why is that? And is it possible to define somewhat a function in that way, which takes one argument (func
), then a list of variable arguments args
before named arguments? If not, what are my possibilities?
The catch-all *args
parameter must come after any explicit arguments:
def foo(func, named_arg=None, *args):
If you also add the catch-all **kw
keywords parameter to a definition, then that has to come after the *args
parameter:
def foo(func, named_arg=None, *args, **kw):
Mixing explicit keyword arguments and the catch-all *args
argument does lead to unexpected behaviour; you cannot both use arbitrary positional arguments and explicitly name the keyword arguments you listed at the same time.
Any extra positionals beyond func
are first used for named_arg
which can also act as a positional argument:
>>> def foo(func, named_arg = None, *args):
... print func, named_arg, args
...
>>> foo(1, 2)
1 2 ()
>>> foo(1, named_arg=2)
1 2 ()
>>> foo(1, 3, named_arg=2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for keyword argument 'named_arg'
>>> foo(1, 2, 3)
1 2 (3,)
This is because the any second positional argument to foo()
will always be used for named_arg
.
In Python 3, the *args
parameter can be placed before the keyword arguments, but that has a new meaning. Normally, keyword parameters can be specified in the call signature as positional arguments (e.g. call your function as foo(somefunc, 'argument')
would have 'argument'
assigned to named_arg
). By placing *args
or a plain *
in between the positional and the named arguments you exclude the named arguments from being used as positionals; calling foo(somefunc, 'argument')
would raise an exception instead.
No, Python 2 does not allow this syntax.
Your options are:
1) move the named arg to appear before *args
:
def foo(func, named_arg = None, *args):
...
2) use **kwargs
:
def foo(func, *args, **kwagrs):
# extract named_arg from kwargs
...
3) upgrade to Python 3.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With