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:
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" class E(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:
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的灵活性体现在多范式支持和动态类型系统,易用性则源于语法简洁和丰富的标准库。1.灵活性:支持面向对象、函数式和过程式编程,动态类型系统提高开发效率。2.易用性:语法接近自然语言,标准库涵盖广泛功能,简化开发过程。

Python因其简洁与强大而备受青睐,适用于从初学者到高级开发者的各种需求。其多功能性体现在:1)易学易用,语法简单;2)丰富的库和框架,如NumPy、Pandas等;3)跨平台支持,可在多种操作系统上运行;4)适合脚本和自动化任务,提升工作效率。

可以,在每天花费两个小时的时间内学会Python。1.制定合理的学习计划,2.选择合适的学习资源,3.通过实践巩固所学知识,这些步骤能帮助你在短时间内掌握Python。

Python适合快速开发和数据处理,而C 适合高性能和底层控制。1)Python易用,语法简洁,适用于数据科学和Web开发。2)C 性能高,控制精确,常用于游戏和系统编程。

学习Python所需时间因人而异,主要受之前的编程经验、学习动机、学习资源和方法及学习节奏的影响。设定现实的学习目标并通过实践项目学习效果最佳。

Python在自动化、脚本编写和任务管理中表现出色。1)自动化:通过标准库如os、shutil实现文件备份。2)脚本编写:使用psutil库监控系统资源。3)任务管理:利用schedule库调度任务。Python的易用性和丰富库支持使其在这些领域中成为首选工具。

要在有限的时间内最大化学习Python的效率,可以使用Python的datetime、time和schedule模块。1.datetime模块用于记录和规划学习时间。2.time模块帮助设置学习和休息时间。3.schedule模块自动化安排每周学习任务。

Python在游戏和GUI开发中表现出色。1)游戏开发使用Pygame,提供绘图、音频等功能,适合创建2D游戏。2)GUI开发可选择Tkinter或PyQt,Tkinter简单易用,PyQt功能丰富,适合专业开发。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

WebStorm Mac版
好用的JavaScript开发工具

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

禅工作室 13.0.1
功能强大的PHP集成开发环境