Python 为什么不能在子类的 __init__ 中传递 *args 和 **kwargs
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21660834/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't pass *args and **kwargs in __init__ of a child class
提问by Nice Guy
To understand *args and **kwargs I made some searchs about, when I fell on this question *args and **kwargs?
为了理解 *args 和 **kwargs,当我遇到这个问题时,我进行了一些搜索*args 和 **kwargs?
The answer below the chosen answer caught my attention, which is this:
所选答案下方的答案引起了我的注意,这是:
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)
I tried some things on this example and running the code this way:
我在这个例子上尝试了一些东西并以这种方式运行代码:
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')
I got this:
我懂了:
[...]
super(MyFoo, self).__init__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'stack'
Changing to be like super(MyFoo, self).__init__(args, kwargs)
变的像 super(MyFoo, self).__init__(args, kwargs)
the results are:
结果是:
('Python', 2.7) {'stack': 'overflow'}
I think something is being called here
('Python', 2.7) {'stack': 'overflow'}
For some blow mind reasons I'm questioning this: what could be right and wrong in the example above? What would be allowed to do and what wouldn't in real life production?
出于某些令人震惊的原因,我对此提出了质疑:在上面的示例中,什么是对的,什么是错的?在现实生活中,哪些可以做,哪些不能做?
采纳答案by Martijn Pieters
Your Foo.__init__()does notsupport arbitrary keyword arguments. You can add **kwto it's signature to make it accept them:
你Foo.__init__()不会不支持任意关键字参数。您可以添加**kw到它的签名以使其接受它们:
class Foo(object):
def __init__(self, value1, value2, **kw):
print 'I think something is being called here'
print value1, value2, kw
Keyword parameters are matched only with arguments with exact matching keyword names; your Foomethod would need to have Pythonand stackkeyword parameters. If no matching keyword parameter are found but a **kwparameter is, they are collected in that parameter instead.
关键字参数仅与关键字名称完全匹配的参数匹配;您的Foo方法需要有Python和stack关键字参数。如果未找到匹配的关键字参数但**kw参数为,则将它们收集在该参数中。
If your subclass knows that the parent class only has positionalarguments, you can always pass in positionals:
如果你的子类知道父类只有位置参数,你总是可以传入位置参数:
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])
where you now mustpass in two or more arguments to MyFoofor the call to work.
您现在必须传入两个或多个参数才能MyFoo使调用正常工作。
In essence, super().methodnamereturns a reference to the bound method; from there on out it is a normalmethod, so you need to pass in arguments that anymethod can accept. If your method doesn't accept keyword arguments, you get an exception.
本质上,super().methodname返回对绑定方法的引用;从那以后它就是一个普通的方法,所以你需要传入任何方法都可以接受的参数。如果您的方法不接受关键字参数,则会出现异常。
回答by Bryan Oakley
When you do this:
当你这样做时:
super(MyFoo, self).__init__(*args, **kwargs)
It is the same as if you did this, base on how your code is working:
根据您的代码的工作方式,这与您执行此操作的情况相同:
super(MyFoo, self).__init__("python", 2.7, stack="overflow")
However, the __init__function of Foo(from which MyFooinherits) doesn't support a keyword argument named "stack".
然而,__init__功能Foo(从MyFoo继承)不支持名为“栈”关键字参数。
回答by Vasif
The reason is all the arguments are already unpacked into kwargs and it is a dict now. and you are trying to pass it to a normal variables.
原因是所有的论点都已经解包到 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)
Try making the modification at
尝试在
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'
should work..!
应该管用..!
回答by Lincoln Randall McFarland
I think it is worth adding that this can be used to simplify the __init__ signatures in the child classes. The positional arguments are pealed off from left to right so if you add them to the front and pass the rest to args and kwargs you can avoid mistakes from forgetting to add them explicitly to each of the children. There is some discussion about if that is an acceptable exception "explicit is better than implicit" here. For long lists of args in deep hierarchy this may be clearer and easier to maintain.
我认为值得补充的是,这可用于简化子类中的 __init__ 签名。位置参数从左到右剥离,因此如果您将它们添加到前面并将其余部分传递给 args 和 kwargs,您可以避免忘记将它们显式添加到每个孩子的错误。有一个关于如果这是一个可接受的例外“明确优于隐式”一些讨论在这里。对于深层层次结构中的长参数列表,这可能更清晰,更易于维护。
To modify this example, I add not_for_Foo to the front of MyFoo and pass the rest through super.
为了修改这个例子,我将 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
-lrm

