Super返回的是mro列表中的下一个类

Published: 2016-08-02

Tags: Python

关于python类

Python中有两种类(old-style classes)和(new-style classes),两者写法如下,在2.2版本之前,只有旧式类,在3.0版中,无论是否继承自object,都为新式类

# 新式类
class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass


# 旧式类
class OldStyleClass():
    pass

相较于旧式类,新式类主要添加了super关键字,修改了MRO等。旧式类只能通过父类名来初始化父类,新式类可以通过super来初始化,以下例子均使用的新式类

class A(object):
    def __init__(self):
        print 'A'

class B(A):
    def __init__(self):
        print 'B'

b = B()
# output: B

python 不会自动初始化父类,所以上边的代码只会输出一个B,下面使用super对A类进行初始化

class A(object):
    def __init__(self):
        print 'A'

class B(A):
    def __init__(self):
        super(B, self).__init__()
        print 'B'
# output: A
#         B

这样,很容易让人误以为super就是调用父类的意思,其实不然

Super返回的是MRO中的下一个类

MRO全称Method Resolution Order,它代表了类继承的顺序,而super返回的是MRO中的下一个类

super就是干这个的:

def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]

输出AB的那个例子,在尾部添加一行代码 print b.__class__.mro() 输出如下:

[<class '__main__.B'>, <class '__main__.A'>, <type 'object'>]

很清晰的一个类继承顺序。结合super代码马上就会理解为什么会初始化A类了。

从表现来看确实是输出了父类,但是说super调用父类是错误的,看下面的一个多继承例子

一个多类继承的例子

class A(object):
    def __init__(self):
        print 'A'

class B(A):
    def __init__(self):
        print 'B'


class C(object):
    def __init__(self):
        print 'C'

class D(C):
    def __init__(self):
        print 'D'

class E(B, D):
    def __init__(self):
        print 'E'

e = E()

想要把每个类都初始化一次,输出ABCDE,理解了mro和super的实现,就很容易了

先来输出e类的mro看看

[<class '__main__.E'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.D'>, <class '__main__.C'>, <type 'object'>]

由上边的mro可以看到类A之后是类D,所以在E类中想要初始化D类,那么需要给super传递A类

使用super初始化之后的代码如下,可以正确输出ABCDE,且仅输出一次

class A(object):
    def __init__(self):
        print 'A'

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

class C(object):
    def __init__(self):
        print 'C'

class D(C):
    def __init__(self):
        super(D, self).__init__()
        print 'D'

class E(B, D):
    def __init__(self):
        super(E, self).__init__()
        super(A, self).__init__()
        print 'E'

e = E()

A类并不是D类的父类,但是super借助A类与mro输出了D类,就是这样。

参考: