视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
super在多继承中的调用细节
2020-11-27 14:27:43 责编:小采
文档


注:此处以python 3为运行环境,例子摘自《python cookbook》第8章。

python中若子类要实现父类的初始化,主要有两种方法,第一种是直接通过父类名,第二种是利用super方法。在单继承时两者没什么区别,但在多继承时就需要注意一些细微的差距了。实例解释才是硬道理!
1、利用父类名的情况:

Python代码

class Base:

def __init__(self):

print('Base.__init__')

class A(Base):

def __init__(self):

Base.__init__(self)

print('A.__init__')

class B(Base):

def __init__(self):

Base.__init__(self)

print('B.__init__')

class C(A,B):

def __init__(self):

A.__init__(self)

B.__init__(self)

print('C.__init__')


此时实例化C类会输出如下:

Python代码

>>> c = C()

Base.__init__

A.__init__

Base.__init__

B.__init__

C.__init__

>>>


从中可看出Base类被调用了两次。这想必在很多情况下都不是我们想要的结果,所以此时可考虑用super方法。

2、利用super的情况:

Python代码

class Base:

def __init__(self):

print('Base.__init__')

class A(Base):

def __init__(self):

super().__init__()

print('A.__init__')

class B(Base):

def __init__(self):

super().__init__()

print('B.__init__')

class C(A,B):

def __init__(self):

super().__init__() # Only one call to super() here

print('C.__init__')


此时再实例化C类的输出为:

Python代码

>>> c = C()

Base.__init__

B.__init__

A.__init__

C.__init__

>>>


可看出Base类是不是只调用了一次啊!但很遗憾的是,这并不是促使我写这篇博客记录的原因,因为如果仔细观察的话,虽说Base类的确如预期只调用了一次,但你有没有发觉是先输出“B.__init__”而后才输出的“A.__init__”?而且为什么这样就使得Base只初始化了一次?想必你也有点懵逼了吧?其实这一切都得“怪罪”于super在多继承时的调用过程。python在实现一个类(不仅是继承)时,会产生一个方法生成解析顺序列表,该列表可通过类属性 __mro__ 查看之,如本例中是这样的:

Python代码

>>> C.__mro__

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,

<class '__main__.Base'>, <class 'object'>)

>>>


所以在搜索一个属性或方法时,它就会按照这个列表遍历每个类,直到找到第一个匹配这个属性或方法的类为止。而在继承中使用super时,解释器会每遇到一次super就会在该列表上搜索下一个类,直到不再遇到super或列表遍历完为止,然后再类似递归逐层返回。因此本例中搜索过程为:C中遇到super --> 搜索列表中的下一个类,即A --> A中再次遇到super,搜索B --> B中super再现,搜索Base --> 初始化Base类,递归返回。
为了更好的解释该过程,现在请注释掉B类的super所在行:

Python代码

class B(Base):

def __init__(self):

#super().__init__()

print('B.__init__')

class C(A,B):

def __init__(self):

super().__init__() # Only one call to super() here

print('C.__init__')


再次实例化C类,输出如下:

Pythonn代码

>>> c = C()

B.__init__

A.__init__

C.__init__


Base类不再产生输出!为什么?因为B中没了super后,就阻断了列表去搜索Base类,所以也就没有初始化Base了!

下载本文
显示全文
专题