示例,假设我定义了一个函数
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个超级参数。我没有看到解决这个问题的好方法。
我不能成为第一个碰到这个,但我找不到任何答案。
答案 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)
可以正常工作。