为了理解* args和** kwargs我做了一些搜索,当我遇到这个问题*args and **kwargs?
所选答案下面的答案引起了我的注意,这就是:
class Foo(object):
def __init__(self, value1, value2):
# do something with the values
print value1, value2
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print 'myfoo'
super(MyFoo, self).__init__(*args, **kwargs)
我在这个例子上尝试了一些东西并以这种方式运行代码:
class Foo(object):
def __init__(self, value1, value2):
# do something with the values
print 'I think something is being called here'
print value1, value2
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print args, kwargs
super(MyFoo, self).__init__(*args, **kwargs)
foo = MyFoo('Python', 2.7, stack='overflow')
我明白了:
[...]
super(MyFoo, self).__init__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'stack'
更改为super(MyFoo, self).__init__(args, kwargs)
结果是:
('Python', 2.7) {'stack': 'overflow'}
I think something is being called here
('Python', 2.7) {'stack': 'overflow'}
出于某些打击思维的原因,我在质疑这个问题:上面的例子中有什么可能是对的?什么是允许做什么和现实生产中不会做什么?
答案 0 :(得分:16)
您的Foo.__init__()
不支持任意关键字参数。您可以将**kw
添加到其签名中,以使其接受:
class Foo(object):
def __init__(self, value1, value2, **kw):
print 'I think something is being called here'
print value1, value2, kw
关键字参数仅与具有完全匹配关键字名称的参数匹配;您的Foo
方法需要有Python
和stack
个关键字参数。如果找不到匹配的关键字参数但**kw
参数 ,则会在该参数中收集它们。
如果你的子类知道父类只有位置参数,你总是可以传入位置:
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print args, kwargs
while len(args) < 2:
args += kwargs.popitem()
super(MyFoo, self).__init__(*args[:2])
您现在必须将两个或多个参数传递给MyFoo
以使调用工作。
实质上,super().methodname
返回对绑定方法的引用;从那里开始它是一个普通方法,所以你需要传入任何方法可以接受的参数。如果您的方法不接受关键字参数,则会出现异常。
答案 1 :(得分:4)
原因是所有的参数都已经解压缩为kwargs并且它现在是一个dict。并且您正试图将其传递给正常变量。
def bun(args,kwargs):
print 'i am here'
print kwargs
def fun(*args,**kwargs):
print kwargs
bun(*args,**kwargs)
fun(hill=3,bi=9) # will fail.
def bun(*args,**kwargs):
print 'i am here'
print kwargs
def fun(*args,**kwargs):
print kwargs
bun(*args,**kwargs) # will work.
fun(hill=3,bi=9)
尝试在
进行修改class Foo(object):
def __init__(self, *value1, **value2):
# do something with the values
print 'I think something is being called here'
print value1, value2
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print args, kwargs
super(MyFoo, self).__init__(*args, **kwargs)
foo = MyFoo('Python', 2.7, stack='overflow'
应该工作..!
答案 2 :(得分:3)
执行此操作时:
super(MyFoo, self).__init__(*args, **kwargs)
就像你这样做一样,基于代码的工作方式:
super(MyFoo, self).__init__("python", 2.7, stack="overflow")
然而,Foo的 init 函数(MyFoo继承的函数)不支持名为“stack”的关键字参数。
答案 3 :(得分:0)
我认为值得补充的是,这可以用来简化子类中的__init__签名。位置参数从左到右被剥离,因此如果将它们添加到前面并将其余部分传递给args和kwargs,则可以避免错误而忘记将它们显式添加到每个子节点。有一些关于这是否是可接受的例外的讨论“显性优于隐式”here。对于深层次结构中的args的长列表,这可能更清晰,更容易维护。
要修改此示例,我将not_for_Foo添加到MyFoo的前面,并将其余内容传递给super。
class Foo(object):
def __init__(self, a_value1, a_value2, a_stack=None, *args, **kwargs):
"""do something with the values"""
super(Foo, self).__init__(*args, **kwargs) # to objects constructor fwiw, but object.__init__() takes no args
self.value1 = a_value1
self.value2 = a_value2
self.stack = a_stack
return
def __str__(self):
return ', '.join(['%s: %s' % (k, v) for k, v in self.__dict__.items()])
class MyFoo(Foo):
def __init__(self, not_for_Foo, *args, **kwargs):
# do something else, don't care about the args
super(MyFoo, self).__init__(*args, **kwargs)
self.not_for_Foo = not_for_Foo # peals off
self.myvalue1 = 'my_' + self.value1 # already set by super
if __name__ == '__main__':
print 'Foo with args'
foo = Foo('Python', 2.7, 'my stack')
print foo
print '\nMyFoo with kwargs'
myfoo = MyFoo('my not for foo', value2=2.7, value1='Python', stack='my other stack')
print myfoo
$ python argsNkwargs.py
Foo with args
value2: 2.7, value1: Python, stack: my stack
MyFoo with kwargs
myvalue1: my_Python, not_for_Foo: my not for foo, value2: 2.7, value1:
Python, stack: my other stack
-lrm