我一直在阅读有关继承的内容,但我似乎无法理解为什么这会给我一个错误(使用Python 2.7.x)。
class A(object):
def __init__(self, value):
super(A, self).__init__()
print 'First %s' % value
class B(object):
def __init__(self, value):
super(B, self).__init__()
print 'Second %s' % value
class Log(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
print 'Log'
x = Log(1000, 2222)
// Error: __init__() takes exactly 2 arguments (1 given)
# Traceback (most recent call last):
# File "<maya console>", line 21, in <module>
# File "<maya console>", line 13, in __init__
# File "<maya console>", line 3, in __init__
# TypeError: __init__() takes exactly 2 arguments (1 given) //
答案 0 :(得分:5)
前言:我在这里解释MRO的尝试非常不足。如果你有45分钟,来自PyCon 2015的Raymond Hettinger this talk做了 很多 更好的工作。具体而言,遍历“兄弟姐妹”的想法可能会产生误导。相反,super
来电只是遵循MRO,(请参阅help(Log)
)。
尽管存在这种情况,但实际上这是一个很好的问题。
考虑稍加修改的代码:
class A(object):
def __init__(self, value):
super(A, self).__init__()
print 'A got: %s' % value
class B(object):
def __init__(self, value):
super(B, self).__init__()
print 'B got: %s' % value
class Log(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
print 'Log'
我们可以毫无问题地创建A和B的实例:
a = A("aa") # A got: aa
b = B("bb") # B got: bb
但是当我们尝试创建Log实例时,我们得到一个例外:
c = Log(123,456)
Traceback (most recent call last): File "temp2.py", line 21, in c = Log(123, 456) File "temp2.py", line 13, in __init__ A.__init__(self, a) File "temp2.py", line 3, in __init__ super(A, self).__init__() TypeError: __init__() takes exactly 2 arguments (1 given)
为了弄清楚这里发生了什么,我们可以默认为value
参数(我使用None
):
class A(object):
def __init__(self, value=None):
super(A, self).__init__()
print 'A got: %s' % value
class B(object):
def __init__(self, value=None):
super(B, self).__init__()
print 'B got: %s' % value
class Log(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
print 'Log'
现在我们的代码运行没有错误:
c = Log(123, 456)
B got: None A got: 123 B got: 456 Log
但输出可能会让您感到困惑:为什么要创建2个B实例?或为什么指定参数默认值很重要?
好吧,请考虑以下(再次,略微修改)代码:
class A(object):
def __init__(self, value=None):
print 'A got: %s' % value
super(A, self).__init__()
class B(object):
def __init__(self, value=None):
print 'B got: %s' % value
super(B, self).__init__()
class Log(A, B):
def __init__(self, a, b):
print("Before A")
A.__init__(self, a)
print("Before B")
B.__init__(self, b)
print 'Log'
现在,当我们尝试创建c
对象时:
c = Log(123, 456)
我们得到:
Before A A got: 123 B got: None Before B B got: 456 Log
这里发生的事情是super(A, self).__init__()
实际上正在调用B.__init__()
。
这是因为super()
将在父母寻找某人实施该方法之前遍历兄弟姐妹。
在这种情况下,它找到了B的__init__
方法。 B的__init__
方法然后也会查找兄弟姐妹然后是父母,但因为B没有兄弟姐妹(由Log
类定义 - self
是一个实例),B的__init__
调用object.__init__
实际上什么也没做。
换句话说(init
是__init__
的简写):
Log.init()
A.init()
super(A, self).init() --> B.init()
super(B, self).init() --> object.init()
B.init()
super(B, self).init() --> object.init()
super
A.init()
内B.init()
找到object.init()
(而不是self
的原因是因为首先搜索了兄弟姐妹。并且在Log(A,B)
(B
{ {1}}),将在父类之前检查super
。
这不会像您可能注意到的那样朝着另一个方向发展,因此 一些阅读: 编辑:要解决此问题,您可以明确调用超类 或者,由于 两者都会输出你想要的东西:B.init()
内的A.init()
将找不到object.init()
,而是找到Log
{1}}。同样,这是因为在B
的上下文中,{/ 1}}将在 A
之后检查,然后是父类object
。< / p>
__init__
,而不是依赖super()
:class A(object):
def __init__(self, value):
object.__init__(self)
print 'First %s' % value
class B(object):
def __init__(self, value):
object.__init__(self)
print 'Second %s' % value
class Log(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
print 'Log'
x = Log(1000, 2222)
object.__init__()
实际上无效,您只需将代码重写为:class A(object):
def __init__(self, value):
print 'First %s' % value
class B(object):
def __init__(self, value):
print 'Second %s' % value
class Log(A, B):
def __init__(self, a, b):
A.__init__(self, a)
B.__init__(self, b)
print 'Log'
x = Log(1000, 2222)
First 1000
Second 2222
Log