super在多重继承中如何与类的__mro__属性交互? [英] How does `super` interacts with a class's `__mro__` attribute in multiple inheritance?

查看:72
本文介绍了super在多重继承中如何与类的__mro__属性交互?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,我阅读了 super的官方文档.
在其中提到的多重继承将由类的__mro__属性决定.
所以我做了一些实验,但结果令我惊讶.

Today, I read the official doc of super.
In which it mentioned multiple inheritance will be decided by the __mro__ attribute of a class.
So I did a bit experiment, but its result surprised me.

# 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.

下面是我上面提到的官方文档的一部分,它说:

Below is part of the official doc I mentioned above, it says:

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()进行调用时,它会调用Motherp(),但是Mother不在GrandFather__mro__中,并且其顺序低于__mro__.

By combining this doc and the result of my experiment. The most confusing part is that when calling with super(GrandFather, s).p() it calls the p() of Mother, but Mother isn't in GrandFather's __mro__, and it is on very inferior order of Son's __mro__.

经过深思熟虑.我得到了一个合理的解释,该解释表明官方文档的不完整或不足:
就是说,当与super(type, instance)一起使用时,super函数将从class的构建者class__mro__属性中搜索,而不从您传递的type__mro__属性中进行搜索.即使满足isinstance(instance, type)条件,也可以更改为super.

After a bit pondering. I got a plausible explanation which indicate the incompleteness or deficiency of the official doc:
That is when using with super(type, instance), the super function will search from the __mro__ attribute of the class from who your instance is build, but not the __mro__ attribute of the type you passed to super, even if it satisfied the isinstance(instance, type) condition.

所以当您键入super(Class, instance)时发生了什么:

So what happened when you typed super(Class, instance) is:

  1. Python检查isinstance(instance, Class)是否为True.
  2. Python找到instance__class__属性,
    获取instance.__class____mro__属性.
  3. Python在步骤2的__mro__元组中找到传递给superClass索引.
  4. Python将step3的索引加1,用它来获取步骤2的__mro__元组中的对应类,并返回此对应类的超级委托.
  5. 如果步骤4中的索引长度超过步骤2的__mro__的长度,则返回步骤2的__mro__中的最后一个类的委托,这是object类.
  1. Python check if isinstance(instance, Class) is True.
  2. Python find the __class__ attribute of instance,
    get the the instance.__class__'s __mro__ attribute.
  3. Python find the index of Class you passed to super in the __mro__ tuple in step2.
  4. Python add the index of step3 by 1, use it to get the corresponding class in __mro__ tuple of step 2, and return the super delegate of this corresponding class.
  5. If the index in step4 exceed length of __mro__ of step2, the delegate of last class in __mro__ of step2 is returned, which is the object class.

我的理解正确吗?
如果我错了,supertype__mro__交互的正确机制是什么?
如果我是对的,我应该如何提出有关python官方doc修改的问题?
因为我认为有关此项目的当前版本可能会误导人.

Is my understanding right?
If I'm wrong, what's the correct mechanism that super interacts with type's __mro__?
If I'm right, how should I raise an issue for python official doc modification?
Because I think the current version about this item could be misleading.

PS:该测试由Python 2.7.6 within IPython 3.2.1完成.

PS: This test was done by Python 2.7.6 within IPython 3.2.1.

推荐答案

查看Son__mro__:

__main__.Son, __main__.Father, __main__.GrandFather, __main__.Mother, object

根据文档:

该类型的__mro__属性列出了方法分辨率搜索顺序

The __mro__ attribute of the type lists the method resolution search order

因此,将根据__mro__列表中从左到右的顺序搜索方法.调用super(type, instance)会将起始位置更改为指定为第二个参数的实例的类的__mro__列表中作为super()的第一个参数的类型(如果传递给super的第二个参数是一个实例) ):

So methods will be searched according to the order in the __mro__ list, from left to right. Call of super(type, instance) will change the starting position to the type specified as the first argument of super() in the __mro__ list of the class of the instance specified as the second argument (if the second argument passed to super is a instance):

super(Son, s)将代理到__main__.Father

super(Father, s)将代理到__main__.GrandFather

super(GrandFather, s)将代理__main__.Mother

super(Mother, s)将代理object

有趣的部分是为什么Son__mro__如此.换句话说,为什么母亲要追随祖父.这是因为线性化在python中是如何工作的:

The interesting part is why __mro__ of Son is like it is. In other words why Mother is after GrandFather. This is because of how the linearization is working in python:

C的线性化是C的总和加上父级线性化和父级列表的合并.

the linearization of C is the sum of C plus the merge of the linearizations of the parents and the list of the parents.

请参阅您提到的文档中的示例,它解释了一个非常类似的情况.

See the examples in the documentation you mentioned, it explains a very similar case.

这样最终结果实际上是正确的:super(GrandFather, s).p()应该是I'm female.

So that final result is actually correct: super(GrandFather, s).p() should be I'm female.

这篇关于super在多重继承中如何与类的__mro__属性交互?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆