Python的“超级”做正确的事情? [英] How does Python's "super" do the right thing?

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

问题描述

我运行的是Python 2.5,所以这个问题可能不适用于Python 3.当你使用多个继承创建一个钻石类层次结构并创建一个派生类的对象时,Python会执行Right Thing(TM)。它调用派生大多数类的构造函数,然后它的父类从左到右列出,然后祖父类。我熟悉Python的 MRO ;这不是我的问题。我很好奇如何从super返回的对象实际上设置为在父类中调用正确的顺序进行通信。考虑这个例子代码:

 #!/ usr / bin / python 

类A :
def __init __(self):printA init

class B(A):
def __init __(self):
printB init
super(B,self).__ init __()

class C(A):
def __init __(self):
printC init
super(C,self).__ init __()

class D(B,C):
def __init __(self):
printD init
super (D,self).__ init __()

x = D()



<代码执行直观的事情,它打印:

  D init 
B init
C init $ b但是,如果你在B的init函数中注释掉对super的调用,那么就不会有一个A也不调用C的init函数。这意味着B的调用super不知何故知道C在整体类层次结构中的存在。我知道super返回一个代理对象与重载的get操作符,但是如何由对象返回的对象在D的初始化定义传递C的存在对B返回的对象在B的init定义的对象?是超级使用的后续调用的信息是否存储在对象本身上?如果是,为什么不是super而不是self.super?



编辑:Jekke非常正确地指出,它不是self.super因为super是类的一个属性,不是类的实例。从概念上讲,这是有意义的,但在实践中,超级不是类的属性!你可以在解释器中通过两个类A和B来测试它,其中B从A继承,并调用 dir(B)。它没有超级 __超级__ 属性。

解决方案

更改你的代码到这里,我想它会解释的东西(可能 super 正在看哪里,比如说, B __ mro __ ?):

  class A(object):
def __init __(self):
printA init
print self .__ class __.__ mro__

class B ):
def __init __(self):
printB init
print self .__ class __.__ mro__
super(B,self).__ init __()
b $ b class C(A):
def __init __(self):
printC init
print self .__ class __.__ mro__
super(C,self).__ init ()

class D(B,C):
def __init __(self):
printD init
print self .__ class __.__ mro__
super(D,self).__ init __()

x = D()



<如果你运行它,你会看到:

  D init 
(< class'__main __。D' >,< class'__main __。B'>,< class'__main __。C'>,< class'__main __。A'>,< type'object'>)
B init
(< class'__main __。D'>,< class'__main __。B'>,< class'__main __。C'>,< class'__main __。A'> < type'object'>)
C init
(< class'__main __。D'>,< class'__main __。B'>,< class'__main __。C' >,< class'__main __。A'>,< type'object'>)
A init
(< class'__main __。D'>,< class'__main__ .b'>,< class'__main __。C'>,< class'__main __。A'>,< type'object'>)
pre>

此外,值得一试的 Python的Super是nifty ,但您不能使用它


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

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?

Edit: 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.

解决方案

Change your code to this and I think it'll explain things (presumably super is looking at where, say, B is in the __mro__?):

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

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

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

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

x = D()

If you run it you'll see:

D init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
B init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
C init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
A init
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)

Also it's worth checking out Python's Super is nifty, but you can't use it.

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

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