Python的“超级"是如何做到的?做正确的事? [英] How does Python's "super" do the right thing?

查看:19
本文介绍了Python的“超级"是如何做到的?做正确的事?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我运行的是 Python 2.5,所以这个问题可能不适用于 Python 3.当您使用多重继承创建菱形类层次结构并创建最派生类的对象时,Python 会做正确的事情 (TM).它调用最派生类的构造函数,然后是从左到右列出的父类,然后是祖父类.熟悉Python的MRO;那不是我的问题.我很好奇从 super 返回的对象实际上如何设法以正确的顺序与父类中的 super 调用进行通信.考虑这个示例代码:

I'm running Python 2.5, so this question may not apply to Python 3. When you make a diamond class hierarchy using multiple inheritance and create an object of the derived-most class, Python does the Right Thing (TM). It calls the constructor for the derived-most class, then its parent classes as listed from left to right, then the grandparent. I'm familiar with Python's MRO; that's not my question. I'm curious how the object returned from super actually manages to communicate to calls of super in the parent classes the correct order. Consider this example code:

#!/usr/bin/python

class A(object):
    def __init__(self): print "A init"

class B(A):
    def __init__(self):
        print "B init"
        super(B, self).__init__()

class C(A):
    def __init__(self):
        print "C init"
        super(C, self).__init__()

class D(B, C):
    def __init__(self):
        print "D init"
        super(D, self).__init__()

x = D()

代码做了直观的事情,它打印:

The code does the intuitive thing, it prints:

D init
B init
C init
A init

但是,如果在 B 的 init 函数中注释掉对 super 的调用,则 A 和 C 的 init 函数都不会被调用.这意味着 B 对 super 的调用以某种方式知道 C 在整个类层次结构中的存在.我知道 super 返回一个带有重载 get 运算符的代理对象,但是在 D 的 init 定义中 super 返回的对象如何将 C 的存在传达给 B 的 init 定义中由 super 返回的对象?后续调用 super 使用的信息是否存储在对象本身上?如果是这样,为什么不是 super 而是 self.super?

However, if you comment out the call to super in B's init function, neither A nor C's init function is called. This means B's call to super is somehow aware of C's existence in the overall class hierarchy. I know that super returns a proxy object with an overloaded get operator, but how does the object returned by super in D's init definition communicate the existence of C to the object returned by super in B's init definition? Is the information that subsequent calls of super use stored on the object itself? If so, why isn't super instead self.super?

Jekke 非常正确地指出它不是 self.super,因为 super 是类的属性,而不是类的实例.从概念上讲,这是有道理的,但实际上 super 也不是类的属性!您可以通过创建两个类 A 和 B(其中 B 继承自 A)并调用 dir(B) 在解释器中测试这一点.它没有 super__super__ 属性.

Jekke quite rightly pointed out that it's not self.super because super is an attribute of the class, not an instance of the class. Conceptually this makes sense, but in practice super isn't an attribute of the class either! You can test this in the interpreter by making two classes A and B, where B inherits from A, and calling dir(B). It has no super or __super__ attributes.

推荐答案

我在下面提供了一堆链接,它们比我希望的更详细、更准确地回答了您的问题.然而,我也会用我自己的话来回答你的问题,以节省你一些时间.我会用积分来表示 -

I have provided a bunch of links below, that answer your question in more detail and more precisely than I can ever hope to. I will however give an answer to your question in my own words as well, to save you some time. I'll put it in points -

  1. super 是一个内置函数,而不是一个属性.
  2. Python 中的每个类型(类)都有一个 __mro__ 属性,用于存储该特定实例的方法解析顺序.
  3. 每次调用 super 的形式都是 super(type[, object-or-type]).让我们暂时假设第二个属性是一个对象.
  4. 在超级调用的起点,对象是派生类的类型(比如说 DC).
  5. super 在指定为第一个参数的类(在本例中为 DC 之后的类)之后,在 MRO 中的类中查找匹配(在您的情况下为 __init__)的方法.
  6. 当找到匹配的方法时(比如在 BC1 类中),就会调用它.
    (此方法应该使用 super,所以我假设它确实如此 - 请参阅 Python 的 super 很漂亮但不能使用 - 下面的链接)然后该方法会在对象的类的 MRO 中搜索下一个方法,位于 BC1 的右侧.
  7. 反复冲洗,直到找到并调用所有方法.
  1. super is a builtin function, not an attribute.
  2. Every type (class) in Python has an __mro__ attribute, that stores the method resolution order of that particular instance.
  3. Each call to super is of the form super(type[, object-or-type]). Let us assume that the second attribute is an object for the moment.
  4. At the starting point of super calls, the object is of the type of the Derived class (say DC).
  5. super looks for methods that match (in your case __init__) in the classes in the MRO, after the class specified as the first argument (in this case classes after DC).
  6. When the matching method is found (say in class BC1), it is called.
    (This method should use super, so I am assuming it does - See Python's super is nifty but can't be used - link below) That method then causes a search in the object's class' MRO for the next method, to the right of BC1.
  7. Rinse wash repeat till all methods are found and called.

示例说明

 MRO: D,B,C,A,object  

  1. super(D, self).__init__() 被调用.isinstance(self, D) => True
  2. 在 MRO 中 D 右侧的类中搜索下一个方法.

  1. super(D, self).__init__() is called. isinstance(self, D) => True
  2. Search for next method in the MRO in classes to the right of D.

B.__init__ 找到并调用

<小时>

  1. B.__init__ 调用 super(B, self).__init__().

isinstance(self, B) => 假
isinstance(self, D) => True

isinstance(self, B) => False
isinstance(self, D) => True

因此,MRO 是相同的,但是搜索继续在 B 的右侧,即 C、A、对象被一个一个地搜索.下一个 __init__ 被调用.

Thus, the MRO is the same, but the search continues to the right of B i.e. C,A,object are searched one by one. The next __init__ found is called.

依此类推.

超级解释
http://www.python.org/download/releases/2.2.3/descrintro/#cooperation
使用 super 时要注意的事项
http://fuhm.net/super-harmful/
Pythons MRO 算法:
http://www.python.org/download/releases/2.3/mro/
super 的文档:
http://docs.python.org/library/functions.html
此页面底部有一个关于超级的不错的部分:
http://docstore.mik.ua/orelly/other/python/0596001886_pythonian-chp-5-sect-2.html

我希望这有助于澄清.

这篇关于Python的“超级"是如何做到的?做正确的事?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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