author: 波比小金刚
千里之行,始于足下。 几乎所有的编程语言都是始于数据存储、运算、逻辑... so, 开始我们的python旅程。 本章节代码都在./code/chapter18.py 图片没加载出来,请直接下载并打开对应的html页面
简介
记录各路好汉摸索出来的一些知识点
1. super()
语法:
super(class, self).someFunc() # 调用父类函数
super(class, self).__init__(*args) # 调用父类构造
super 关键点1:super()只能用于新式类中
, 所谓新式类,旧类的,关键就是看是不是有基类,有基类的就是形式类,比如class A(object),所以class A()自然就是旧式类了。- 在单继承的情况下,super()和我们想的一样很简单。
这种情况下super() 等价于使用Parent.init(self) or Paren.sayHello()
# 单继承
class A(object):
def __init__(self, a, b):
self.a = a
self.b = b
def sayHello(self):
print('this is class A, a={},b={}'.format(self.a, self.b))
class B(A):
def __init__(self, a, b, c):
super(B, self).__init__(a,b)
self.c = c
def sayHello(self):
super(B, self).sayHello()
print('this is b call')
b = B('b','also b','test')
b.sayHello()
# this is class A, a=b,b=also b
# this is b call
- mro
super 关键点2:super 其实和父类没有实质性的关联
多重继承下,super就没有那么简单了。
我们先看一个多重继承的demo:
# 多重继承
class Base(object):
def __init__(self):
print('enter Base')
print('out Base')
class A(Base):
def __init__(self):
print('enter A')
super(A, self).__init__()
print('out A')
class B(Base):
def __init__(self):
print('enter B')
super(B, self).__init__()
print('out B')
class C(A, B):
def __init__(self):
print('enter C')
super(C, self).__init__()
print('out C')
c = C()
#enter C
#enter A
#enter B
#enter Base
#out Base
#out B
#out A
#out C
这个案例的继承关系很简单:
其中,Base 是父类,A, B 继承自 Base, C 继承自 A, B
如果super是表示调用父类的话,上边的执行应该是 C->A->Base->B
但是实际执行顺序是 C->A->B->Base
所以:
super 关键点2:super 其实和父类没有实质性的关联
现在我们来试着搞清楚super的实现原理。
首先我们要理解一个概念:
mro
方法解析顺序(Method Resolution Order, MRO)列表,它代表了类继承的顺序
可以打印C.mro() 看看结果
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]
所以可以解释上边的执行了,先执行C的构造器函数。执行print('enter C')之后,开始执行super(c)(#简写了就),这个super执行后会返回下一个执行顺序的函数 也就是A , 所以跟着执行print(A),然后执行super(A),然后返回下一个执行顺序就是B, 所以执行print(B),再是super(B),依次类推。
mro采用C3 线性化算法,遵循一下规则:
- 子类永远在父类前面
- 如果有多个父类,会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
super的原理:
super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls)+1]
so:
关键点3:super不是父类,而是继承顺序的下一个类
try:
# 多重继承
class D(object):
def __init__(self):
print('enter D')
super(D, self).__init__()
print('out D')
class Base(object):
def __init__(self):
print('enter Base')
print('out Base')
class A(D,Base):
def __init__(self):
print('enter A')
super(A, self).__init__()
print('out A')
class B(Base):
def __init__(self):
print('enter B')
super(B, self).__init__()
print('out B')
class C(A, B):
def __init__(self):
print('enter C')
super(C, self).__init__()
print('out C')
c = C() #-->[C->A->D->B->Base]
新增加一个 D ,分别把它加到 C , A, B 的基类。试试输出的顺序。 注意加到 base 前和后 是不同的结果哦。
注意使用类似Parent.init(self)的方式就不会再有mro算法的魔力。 上面的案例中如果把A中的super()换成是 Base.init(self)的话,就不会再顺序执行了,会直接跳到Base中,而忽略了B。 如果把A中的super()换成是 super(C, self).init()则会造成死循环。
关键点3:super()可以避免重复调用
# 避免重复
class E(object):
def __init__(self):
print('enter E')
print('out E')
class F(E):
def __init__(self):
print('enter F')
E.__init__(self) #-> 这样使用的哦,会重复
print('out F')
class G(F, E):
def __init__(self):
print('enter G')
F.__init__(self)
E.__init__(self)
print('out G')
g = G()
# enter G
# enter F
# enter E
# out E
# out F
# enter E
# out E
# out G
看上述的例子,发现E 被执行了两次,因为里头没有使用super()方式。 使用super()方式就会只被执行一次。