用`* args`,关键字参数成为位置?

时间:2017-09-10 18:33:46

标签: python python-2.7 function arguments keyword

示例,假设我定义了一个函数

def myfunc(a=1, *args):
    print(a)
    # *args have some other functionality, for example passed to a class instance, or whatever

问题是:在调用myfunc时,我无法首先传递*args的预期位置参数,然后传递关键字参数a。例如,如果预期的*args只包含一个数字,我就无法做到

myfunc(3, a=4)

这会引发错误,说明收到的多个作业。我显然无法做myfunc(a=4, b=5, 3)。我只能这样做

myfunc(4, 3)

现在看来,*args,关键字参数a真的变成了位置?

这里的示例是一个函数,但它也适用于类。假设一个__init__(a=3, *args)的子类想要一些关键字参数a和其他99个必需的参数传递给super。我不想在子类中重复99个参数定义,而是执行*args并将其传递给super。但现在关键字参数a变为位置。

这个类和子类示例是我编码中的真正问题。我想要一个带有可选的关键字参数a的子类,然后需要99个超级参数。我没有看到解决这个问题的好方法。

我不能成为第一个碰到这个,但我找不到任何答案。

2 个答案:

答案 0 :(得分:2)

>>> import inspect >>> def myfunc(a=1, *args): ... print(a) >>> inspect.signature(myfunc).parameters['a'].kind <_ParameterKind.POSITIONAL_OR_KEYWORD: 1> 不仅仅是位置:

>>> myfunc(a=4)
4

实际上它可以作为keyword-argument传递:

*args

但是,正如您所指出的,只要您想提供后续位置参数,就必须将其作为位置参数提供。但这与>>> def myfunc2(a, b): ... print(a) >>> myfunc2(1, a=2) TypeError: myfunc2() got multiple values for argument 'a' 无关,这就是位置参数的工作方式:

*args

它必须是所有位置参数中的第一个所有参数都必须按名称传递。

然而*args, **kwargs使情况有些复杂化,因为它只收集位置参数。这意味着如果它应该收集任何,你还必须按位置传递所有先前的参数。

但是如果你想要推出自己的特殊情况,你可以只接受>>> def myfunc3(*args, **kwargs): ... if 'a' in kwargs: ... a = kwargs.pop('a') ... else: ... a = args[0] ... args = args[1:] ... print(a, args, kwargs) >>> myfunc3(1, a=2) 2 (1,) {} >>> myfunc3(2, 1) 2 (1,) {} 并首先检查它是否作为关键字(命名)参数传递,如果不是,则作为第一个位置参数:< / p>

isset

这应该给你你想要的结果,但你需要在文档中明确如何传递参数,因为它有点打破了Pythons签名模型的语义。

答案 1 :(得分:1)

Python 3引入了仅关键字的参数:https://www.python.org/dev/peps/pep-3102/

因此您可以这样做:

def myfunc(*args, a=1):
    print(a)

然后myfunc(3, a=4)可以正常工作。

相关问题