python 多继承详解
|
1
2
3
4
5
6
7
8
9
10
|
class A(object): # A must be new-style class def __init__(self): print "enter A" print "leave A" class B(C): # A --> C def __init__(self): print "enter B" super(B, self).__init__() print "leave B" |
在我们的印象中,对于super(B, self).__init__()是这样理解的:super(B, self)首先找到B的父类(就是类A),然后把类B的对象self转换为类A的对象,然后“被转换”的类A对象调用自己的__init__函数。 有一天某同事设计了一个相对复杂的类体系结构(我们先不要管这个类体系设计得是否合理,仅把这个例子作为一个题目来研究就好),代码如下
代码段4:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class A(object): def __init__(self): print "enter A" print "leave A" class B(object): def __init__(self): print "enter B" print "leave B" class C(A): def __init__(self): print "enter C" super(C, self).__init__() print "leave C" class D(A): def __init__(self): print "enter D" super(D, self).__init__() print "leave D"classE(B, C) def __init__(self): print "enter E" B.__init__(self) C.__init__(self) print "leave E" class F(E, D): def __init__(self): print "enter F" E.__init__(self) D.__init__(self) print "leave F" |
f = F() ,结果如下:
enter F enter E enter B leave B enter C enter D enter A leave A leave D leave C leave E enter D enter A leave A leave D leave F
明显地,类A和类D的初始化函数被重复调用了2次,这并不是我们所期望的结果!我们所期望的结果是最多只有类A的初始化函数被调用2次——其实这是多继承的类体系必须面对的问题。我们把代码段4的类体系画出来,如下图:
object
| \
| A
| / |
B C D
\ / |
E |
\ |
F
按我们对super的理解,从图中可以看出,在调用类C的初始化函数时,应该是调用类A的初始化函数,但事实上却调用了类D的初始化函数。好一个诡异的问题!
也就是说,mro中记录了一个类的所有基类的类类型序列。查看mro的记录,发觉包含7个元素,7个类名分别为:
F E B C D A object
从而说明了为什么在C.__init__中使用super(C, self).__init__()会调用类D的初始化函数了。 ???
我们把代码段4改写为:
代码段5:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class A(object): def __init__(self): print "enter A" super(A, self).__init__() # new print "leave A" class B(object): def __init__(self): print "enter B" super(B, self).__init__() # new print "leave B" class C(A): def __init__(self): print "enter C" super(C, self).__init__() print "leave C" class D(A): def __init__(self): print "enter D" super(D, self).__init__() print "leave D"class E(B, C): def __init__(self): print "enter E" super(E, self).__init__() # change print "leave E" class F(E, D): def __init__(self): print "enter F" super(F, self).__init__() # change print "leave F" |
f = F(),执行结果:
enter F enter E enter B enter C enter D enter A leave A leave D leave C leave B leave E leave F 可见,F的初始化不仅完成了所有的父类的调用,而且保证了每一个父类的初始化函数只调用一次。
小结
1. super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,
产生了一个super对象;
2. super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
3. super(B, self).func的调用并不是用于调用当前类的父类的func函数;
4. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数
只调用一次(如果每个类都使用super);
5. 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一
个父类函数被调用多次。
一些更深入的问题:各位可以看到,print F.__mro__时发现里面元素的顺序是 F E B C D A object,这就是F的基类查找顺序,至于为什么是这样的顺序,以及python内置的多继承顺序是怎么实现的,这涉及到mro顺序的实现,python 2.3以后的版本中是采用的一个叫做C3的算法,在下篇博客中进行介绍。
python 多继承详解的更多相关文章
- Python super继承详解
MRO(Method resolution order)是python用来解析方法调用顺序的,mro中记录了一个类的所有基类的类类型序列,super不是简单地调用基类的方法,而是按照MRO中的顺序来调 ...
- python 多继承详解-乾颐堂
1 2 3 4 5 6 7 8 9 10 class A(object): # A must be new-style class def __init__(self): prin ...
- 第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解
第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解 一. 引言 上两节介绍了构造方法的语法及参数,说明了构造方法是Python的类创建实例后首先执行的方法,并说明如果类 ...
- (转)python collections模块详解
python collections模块详解 原文:http://www.cnblogs.com/dahu-daqing/p/7040490.html 1.模块简介 collections包含了一些特 ...
- python自定义异常实例详解
python自定义异常实例详解 本文通过两种方法对Python 自定义异常进行讲解,第一种:创建一个新的exception类来拥有自己的异常,第二种:raise 唯一的一个参数指定了要被抛出的异常 1 ...
- Python基础知识详解 从入门到精通(七)类与对象
本篇主要是介绍python,内容可先看目录其他基础知识详解,欢迎查看本人的其他文章Python基础知识详解 从入门到精通(一)介绍Python基础知识详解 从入门到精通(二)基础Python基础知识详 ...
- 《python开发技术详解》|百度网盘免费下载|Python开发入门篇
<python开发技术详解>|百度网盘免费下载|Python开发入门篇 提取码:2sby 内容简介 Python是目前最流行的动态脚本语言之一.本书共27章,由浅入深.全面系统地介绍了利 ...
- Python 字符串方法详解
Python 字符串方法详解 本文最初发表于赖勇浩(恋花蝶)的博客(http://blog.csdn.net/lanphaday),如蒙转载,敬请保留全文完整,切勿去除本声明和作者信息. ...
- [原创]JavaScript继承详解
原文链接:http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html 面向对象与基于对象 几乎每个开发人员都有面向对象语言(比如C++. ...
随机推荐
- python模块subprocess学习
当我们想要调用系统命令,可以使用os,commands还有subprocess模块整理如下: os模块: 1. os.system 输出命令结果到屏幕.返回命令执行状态. >>> o ...
- apache log 按日期记录 格式 <GOOD>-- (转)
在apache的配置文件中找到ErrorLog logs/error_logCustomLog logs/access_log common Linux系统配置方法: 将其改为ErrorLog “| ...
- Apache2.4+Tomcat7 集群
Apache2.4+Tomcat7 集群: 1.下载并安装相对应的软件 apache下载地址:http://httpd.apache.org/ 这里使用apache2.4 tomcat下载地址:htt ...
- Android控件——ImageView
android:orientation="vertical" 修改布局文件垂直排列 放置图片: 1.通过src引入图片: 2.通过background引入背景图片 3.baco ...
- grep常见操作整理(更新)
提取邮箱和URL [root@test88 ~]# cat url_email.txt root@gmail.com,http://blog.peter.com,peter@qq.com [root@ ...
- FineReport——函数
1.VALUE(tableData,col,row)返回tableData中列号为col的值, 行号为row.备注:先从报表数据集中查找,然后再从服务器数据集中查找,返回的是tableData的行数. ...
- [ python ] 类的组合
首先,使用面向对象是一个人狗大战的实例: class Person: def __init__(self, name, hp, aggr, sex): self.name = name self.hp ...
- linux命令(16):mv命令
移动文件:mv /mnt/test.log /home 移动目录:mv -f /mnt/test /home [带-f参数如目的已存在同名文件,则直接覆盖掉] 文件改名:mv /mnt/test /m ...
- 查询 IDE 的版本 方便安装第三方的时候选择
TMD 很多第三方软件 的版本 定义 与 delphi是不一致的. 1.有的是以这个为准.
- node-session
session cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么一些重要的数据就不能存放在 cookie 中 ...