Just put the default arguments before the *args
:
def foo(a, b=3, *args, **kwargs):
Now, b
will be explicitly set if you pass it as a keyword argument or the second positional argument.
Examples:
foo(x) # a=x, b=3, args=(), kwargs={}
foo(x, y) # a=x, b=y, args=(), kwargs={}
foo(x, b=y) # a=x, b=y, args=(), kwargs={}
foo(x, y, z, k) # a=x, b=y, args=(z, k), kwargs={}
foo(x, c=y, d=k) # a=x, b=3, args=(), kwargs={'c': y, 'd': k}
foo(x, c=y, b=z, d=k) # a=x, b=z, args=(), kwargs={'c': y, 'd': k}
Note that, in particular, foo(x, y, b=z)
doesn't work because b
is assigned by position in that case.
This code works in Python 3 too. Putting the default arg after *args
in Python 3 makes it a "keyword-only" argument that can only be specified by name, not by position. If you want a keyword-only argument in Python 2, you can use @mgilson's solution.