I’ve found a behavior in Python that has baffled and irritated me and I was wondering what I got wrong.
I have a function which should take an arbitrary number of arguments and keywords, but in addition should have some default-valued keywords that comprise it’s actual interface:
def foo(my_keyword0 = None, my_keyword1 = 'default', *args, **kws):
for argument in args:
print argument
The problem is that if I try calling foo(1, 2, 3) I’ll only get the printout for 3 and the values 1 and 2 will override my keyword arguments.
On the other hand if I try moving my keywords after the *args or after the **kws it will cause a syntax error. The only solution I found to the problem was to extract the keyword arguments from **kws and setting default values to them:
def foo(*args, **kws):
my_keyword0 = None if 'my_keyword0' not in kws else kws.pop('my_keyword0')
my_keyword0 = 'default' if 'my_keyword1' not in kws else kws.pop('my_keyword1')
for argument in args:
print argument
This is horrible both because it forces me to add pointless code and because the function signature becomes harder to understand – you have to actually read the functions code rather than just look at its interface.
What am I missing? Isn’t there some better way to do this?
Function arguments with default values are still positional arguments, and thus the result you see is correct. When you specify a default value for a parameter, you are not creating a keyword argument. Default values are simply used when the parameters are not provided by a function call.
Note the last error message: as you can see the
1got assigned toargument, and then python discovered thekeywordreferring toargumentagain, and thus raised an error.The
*argsare assigned only after assigning all possible positional arguments.In python2 there is no way to define a keyword-only value other than using
**kwargs. As a workaround you could do something like:In python3 you can define keyword-only arguments:
Note that keyword-only does not imply that it should have a default value.