Python的super()如何处理多重继承?
我在Python面向对象编程方面非常新颖,并且我很难理解super()
函数(新样式类),特别是在涉及多重继承时。
例如,如果你有类似的东西:
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__()
print "that's it"
我没有得到的是: Third()
类会继承两个构造方法吗? 如果是,那么将使用super()运行哪一个,为什么?
如果你想运行另一个呢? 我知道这与Python方法解析顺序(MRO)有关。
Guido本人在他的博客文章Method Resolution Order(包括两次较早的尝试)中详细说明了这一点。
在你的例子中, Third()
将调用First.__init__
。 Python会在类的父项中查找从左到右列出的每个属性。 在这种情况下,我们正在寻找__init__
。 所以,如果你定义
class Third(First, Second):
...
Python首先查看First
,如果First
没有该属性,那么它将查看Second
。
当继承开始跨越路径时,这种情况变得更加复杂(例如,如果First
从Second
继承)。 阅读上面的链接了解更多细节,但是,简而言之,Python将尝试维护每个类在继承列表中出现的顺序,从子类本身开始。
所以,举个例子,如果你有:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
MRO将是[Fourth, Second, Third, First].
顺便说一下:如果Python找不到一致的方法解析顺序,它会引发异常,而不是回到可能让用户感到惊讶的行为。
编辑添加模棱两可的MRO示例:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Third
MRO应该是[First, Second]
还是[Second, First]
? 没有明显的期望,Python会引发一个错误:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
编辑:我看到一些人认为上面的例子没有super()
调用,所以让我解释一下:例子的要点是展示MRO是如何构建的。 他们不打算打印“第一 nsecond 第三”或其他。 当然,你可以 - 也应该玩这个例子,添加super()
调用,看看会发生什么,并且更深入地理解Python的继承模型。 但我的目标是保持简单并展示MRO的构建方式。 正如我解释的那样:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
你的代码和其他答案都是错误的。 他们缺少合作子类工作所需的前两个类中的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("third")
super()
调用在每个步骤中查找MRO中的下一个方法,这就是为什么First和Second必须具有它,否则执行将在Second.__init__()
的末尾停止。
这是我得到的:
>>> Third()
second
first
third
我想简单地说出一些毫无生气的答案,因为当我开始阅读关于如何在Python的多重继承层次结构中使用super()时,我没有立即得到它。
你需要了解的是, super(MyClass, self).__init__()
提供了下一个__init__
方法,根据在完整继承层次结构中使用的方法解析顺序(MRO)算法。
这最后一部分是理解的关键。 我们再来看一下这个例子:
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"
根据这篇关于Guido van Rossum的Method Resolution Order的文章,使用“深度优先从左到右遍历”计算了解决__init__
的命令(在Python 2.3之前):
Third --> First --> object --> Second --> object
删除所有重复项后,除最后一项外,我们得到:
Third --> First --> Second --> object
因此,让我们来看看当我们实例化Third
类的实例时会发生什么,例如x = Third()
。
根据MRO的__init__
第一个被称为第一个。
接下来,根据MRO,在__init__
方法super(Third, self).__init__()
解析为First的__init__
方法,该方法被调用。
里面__init__
首先super(First, self).__init__()
调用__init__
其次的,因为那是MRO决定的!
里面__init__
秒super(Second, self).__init__()
调用__init__
的对象,这相当于什么都没有。 之后, 打印“秒” 。
super(First, self).__init__()
完成后, 打印“first” 。
super(Third, self).__init__()
完成后, 打印出“就是这样” 。
这详细介绍了为什么将Third()结果实例化为:
>>> x = Third()
second
first
that's it
从Python 2.3开始,MRO算法已经得到了改进,在复杂情况下能够很好地工作,但我想大多数情况下,使用“深度优先从左到右遍历”+“去除重复期望的最后一个”仍然有效如果不是这种情况,请发表评论)。 请务必阅读Guido的博客文章!
链接地址: http://www.djcxy.com/p/4531.html上一篇: How does Python's super() work with multiple inheritance?