【发布时间】:2015-11-24 10:16:29
【问题描述】:
今天,我阅读了official doc of super。
其中提到多重继承将由类的__mro__ 属性决定。
于是我做了一些实验,结果让我吃惊。
# CODE PART
class GrandFather(object):
def p(self):
print "I'm old."
class Father(GrandFather):
def p(self):
print "I'm male."
class Mother(object):
def p(self):
print "I'm female."
class Son(Father, Mother):
def p(self):
print "busy, busy, crwaling. "
# EXPERIMENT PART
In [1]: Son.__mro__
Out[1]: (__main__.Son, __main__.Father, __main__.GrandFather, __main__.Mother, object)
In [2]: Father.__mro__
Out[2]: (__main__.Father, __main__.GrandFather, object)
In [3]: Mother.__mro__
Out[3]: (__main__.Mother, object)
In [4]: GrandFather.__mro__
Out[4]: (__main__.GrandFather, object)
In [5]: s = Son()
In [6]: super(Son, s).p()
I'm male.
In [7]: super(Father, s).p()
I'm old.
In [8]: super(Mother, s).p()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-ce4d0d6ef62d> in <module>()
----> 1 super(Mother, s).p()
AttributeError: 'super' object has no attribute 'p'
In [9]: super(GrandFather, s).p()
I'm female.
下面是我上面提到的官方文档的一部分,上面写着:
super(type[, object-or-type])
Return a proxy object that delegates method calls to a parent or sibling class of type.
This is useful for accessing inherited methods that have been overridden in a class.
The search order is same as that used by getattr() except that the type itself is skipped.
The __mro__ attribute of the type lists the method resolution search order
used by both getattr() and super().
The attribute is dynamic and can change whenever the inheritance hierarchy is updated.
If the second argument is an object, isinstance(obj, type) must be true.
通过结合这个文档和我的实验结果。最令人困惑的部分是,当使用super(GrandFather, s).p() 调用时,它调用了Mother 的p(),但Mother 不在GrandFather 的__mro__ 中,而且它的顺序非常劣于@987654331 @的__mro__。
经过一番琢磨。我得到了一个合理的解释,表明官方文档的不完整或不足:
也就是说,当与super(type, instance) 一起使用时,super 函数将从class 的__mro__ 属性中搜索您的instance 的构建者,而不是您传递的type 的__mro__ 属性到super,即使它满足isinstance(instance, type) 条件。
所以当你输入super(Class, instance) 时发生的事情是:
- Python 检查
isinstance(instance, Class)是否为真。 - Python 找到
instance的__class__属性,
获取instance.__class__的__mro__属性。 - Python 在第二步的
__mro__元组中找到你传递给super的Class的索引。 - Python将step3的索引加1,用它来获取step2的
__mro__元组中对应的类,并返回这个对应类的super delegate。 - 如果step4的索引超过step2的
__mro__的长度,则返回step2的__mro__最后一个类的delegate,即object类。
我的理解对吗?
如果我错了,super 与type 的__mro__ 交互的正确机制是什么?
如果我是对的,我应该如何提出 python 官方文档修改的问题?
因为我认为关于这个项目的当前版本可能会产生误导。
PS:本次测试由Python 2.7.6 within IPython 3.2.1完成。
【问题讨论】:
-
好问题,令人惊讶的行为!
标签: python inheritance superclass super