多重继承如何与 super() 和不同的 __init__() 参数一起工作?
Posted
技术标签:
【中文标题】多重继承如何与 super() 和不同的 __init__() 参数一起工作?【英文标题】:How does multiple inheritance work with the super() and different __init__() arguments? 【发布时间】:2013-05-27 03:29:12 【问题描述】:我只是在深入研究一些更高级的 python 主题(嗯,至少对我来说是高级的)。我现在正在阅读有关多重继承以及如何使用 super() 的内容。我或多或少了解 super 函数的使用方式,但是 (1) 这样做有什么问题?:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
First.__init__(self)
Second.__init__(self)
print "that's it"
关于 super(),Andrew Kuchlings paper on Python Warts 说:
当 Derived 类继承时 super() 的使用也是正确的 来自多个基类,其中部分或全部具有 init 方法
所以我把上面的例子改写如下:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(self)
print "that's it"
然而,这只会运行它可以找到的第一个 init,它位于 First
中。 (2) 可以使用super()
运行来自First
和Second
的init,如果可以,如何运行? 运行super(Third, self).__init__(self)
两次只是首先运行。init() 两次..
增加一些混乱。如果继承类的 init() 函数采用不同的参数会怎样。例如,如果我有这样的事情:
class First(object):
def __init__(self, x):
print "first"
class Second(object):
def __init__(self, y, z):
print "second"
class Third(First, Second):
def __init__(self, x, y, z):
First.__init__(self, x)
Second.__init__(self, y, z)
print "that's it"
(3) 如何使用 super() 为不同的继承类初始化函数提供相关参数?
欢迎所有提示!
ps。由于我有几个问题,我将它们加粗并编号..
【问题讨论】:
super(Class, self)
返回一个对象,因此您不应使用.__init__(self)
调用它,而应使用.__init__()
。您可以在答案中看到这一点,但您原来的第一个代码返回异常 TypeError: __init__() takes exactly 1 argument (2 given)
。
【参考方案1】:
对于问题2,你需要在每个类中调用super:
class First(object):
def __init__(self):
super(First, self).__init__()
print "first"
class Second(object):
def __init__(self):
super(Second, self).__init__()
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
对于问题 3,这是无法做到的,您的方法需要具有相同的签名。但是你可以忽略父类中的一些参数或使用关键字参数。
【讨论】:
所以你的意思是super()的使用依赖于继承类中super()的使用?如果我不控制继承的类怎么办?然后我会像我的第一个示例那样简单地执行 First.__init__(self) 和 Second.__init__(self) 吗? 是的,“super”是一个协作进程,所有类都需要使用该机制,否则它就不起作用。你可以在这里找到更多信息:rhettinger.wordpress.com/2011/05/26/super-considered-super 是的,如果层次结构中的一个类不使用 super,我认为你必须使用“旧式”方式 :) 谢谢。最后一个问题;为什么 super() 仍然添加到语言中?它比“旧式”有什么优势? 我看到了两个优点:您不必显式引用父类,并且在多重继承的情况下您不必调用多个父构造函数......同样在 python3 中,您只有调用 super().something() 而不是 super(Class, self).something() 您说:“在多重继承的情况下,您不必调用多个父构造函数”。不过我不明白,因为如果我调用 super(CurrentClass, self).__init__() (就像我在第二段代码中所做的那样)它只运行第一个继承类的 init 函数而不是所有的 init继承的类。所以这意味着在进行多重继承时不能使用 super() .. 对吗?【参考方案2】:1) 像你在 1 中所做的那样做没有错,如果你想使用基类的属性,那么你必须调用基类 init() 或者即使您使用基类中的方法,该方法使用其自己类的属性,然后您必须调用基类 init()
2) 你不能使用 super 来运行 First 和 Second 的 init,因为 python 使用 MRO(方法解析顺序)
查看以下代码,这是菱形层次结构
class A(object):
def __init__(self):
self.a = 'a'
print self.a
class B(A):
def __init__(self):
self.b = 'b'
print self.b
class C(A):
def __init__(self):
self.c = 'c'
print self.c
class D(B,C):
def __init__(self):
self.d = 'd'
print self.d
super(D, self).__init__()
d = D()
print D.mro()
打印出来:
d
b
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>]
python 的 MRO 是 D,B,C,A
如果 B 没有 init 方法,它适用于 C。
3) 你不能这样做所有的方法都需要有相同的签名。
【讨论】:
以上是关于多重继承如何与 super() 和不同的 __init__() 参数一起工作?的主要内容,如果未能解决你的问题,请参考以下文章