关于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类,就是这样。
参考: