看起来像一个简单的模式,用于允许可变数量的位置参数以及默认名称的arg无效。
我想我可以使用**kwargs
来克服这个问题,但是我做错了什么更直接的方法吗?
为什么不起作用?
class Foo(obect):
"""Baffling"""
def __init__(self, bar=None, *args):
pass
foo = Foo(1) #works
foo = Foo(1, bar=2) # explodes
----> 1 foo = Foo(1, bar='baz')
TypeError: __init__() got multiple values for keyword argument 'bar'
以上代码如何传递重复的bar
关键字参数?
答案 0 :(得分:2)
在Python中,已命名属性在未命名之后使用(例如*args
)。因此,您应该将__init__
更改为:
def __init__(self, *args, bar=None):
这里是示例:
class Foo(object):
"""Baffling"""
def __init__(self, *args, bar=None):
self.bar = bar
foo = Foo(1, bar=2) # explodes
foo.bar
会返回:
Out[...]: 2
P.S。无论如何,混合使用*args
,**kwargs
和命名属性不是一个好主意。我建议您避免这种情况。
答案 1 :(得分:2)
命名参数既可以按位置也可以按名称传递:
>>> def foo(a):
... print(a)
...
>>> foo(1)
1
>>> foo(a=2)
2
如果您传递位置和关键字参数,则会按顺序分配它们。在您的情况下,将1分配给第一个位置参数(bar
),然后bar=2
分配名为bar
的参数。因此,两者都分配给名称bar
,从而产生冲突。
您可以在您的命名对象之后的 之后传递其他参数:
>>> def foo(bar=None, *args):
... print('args=%r, bar=%r' % (args, bar))
...
... foo(2, 1) # bar=2, *args=(1,)
args=(1,), bar=2
在Python3中,您还可以仅将parameter关键字设为:
>>> def foo(*args, bar=None):
... print('args=%r, bar=%r' % (args, bar))
...
... foo(1, bar=2)
args=(1,), bar=2
当您不接受任何可变参数时,此方法也适用:
>>> def foo(*, bar=None):
... print('args=%r, bar=%r' % ('undefined', bar))
...
... foo(bar=2)
args='undefined', bar=2
>>> foo(1, bar=2)
TypeError: foo() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
在Python2中,**kwargs
之后仅允许*args
。您可以通过从kwargs
中弹出命名参数来模拟它们:
>>> def foo(*args, **kwargs):
... bar = kwargs.pop("bar")
... print('args=%r, bar=%r' % (args, bar))
...
... foo(1, bar=2)
args=(1,), bar=2
如果您想要仅命名参数而没有可变位置和命名参数,则必须自己引发错误:
>>> def foo(*args, **kwargs):
... bar = kwargs.pop('bar')
... if args or kwargs:
... raise TypeError
... print('args=%r, bar=%r' % ('undefined', bar))
...
... foo(bar=2)
args='undefined', bar=2
>>> foo(1, bar=2)
TypeError