Вопрос

I need to do something like this:

def func1(a, *args, b="BBB", **kwargs):
    print "a=%s b=%s args=%s kwargs=%s" % (a, b, args, kwargs)

So that calling like this:

func1("AAAA", h="HHH", j="JJJ")

Produces the output:

a=AAAA b=BBB args=() kwargs={'h': 'HHH', 'j': 'JJJ'}

But it is not possible to put a default named argument after *args. (SyntaxError: invalid syntax)

  • Why is this not allowed?
  • Is there any readable way to implement this? The only way I know is b=kwargs.pop("b", "BBB"), but this is not very readable. I would prefer to have this in the function call definition, where it belongs: it is a parameter which will always have a value, either a default value or a user-given value.

EDIT

I could put b in front of args:

def func1(a, b="BBB", *args, **kwargs):
    print "a=%s b=%s args=%s kwargs=%s" % (a, b, args, kwargs)

But that would mean that this call:

func1("AAAA", "CCC", h="HHH", j="JJJ")

Assigns "CCC" to b, which I do not want. I want b to be a named arg, not a possitional arg.

Это было полезно?

Решение

That's perfectly valid in Python 3 (demonstration); PEP 3102 introduced keyword-only arguments.

In Python 2.x you'll have to continue using kwargs.pop, or an appropriate decorator:

Другие советы

In Python 2,

The current Python function-calling paradigm allows arguments to be specified either by position or by keyword. An argument can be filled in either explicitly by name, or implicitly by position.

As a consequence def func1(a, *args, b="BBB", **kwargs) would be ambiguous and is therefore not allowed: in a call func1(1, 2), should args == () and b == 2, or args = (2,) and b == "BBB"?

This is why def func1(a, b="BBB", *args, **kwargs) is, on the other hand, accepted (even though it does not do what you want): b is always passed as the second argument, even in a call like func1(1, c=3, b=2) (it is equivalent to func1(1, 2, c=3)).

As ecatmur noted, Python 3 changed the way arguments are handled, which brings the flexibility you need.

def func1(a, *args, **kwargs):
    b, k = (lambda b="BBBB", **k: b, k)(**kwargs)
    print "a=%s b=%s args=%s kwargs=%s" % (a, b, args, k)

could be an alternative.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top