python的super函数学习
一、为什么要用super?
在Python 2.2以前,通常的做法:
class A:
def __init__(self):
print "enter A"
print "leave A"
class B(A):
def __init__(self):
print "enter B"
A.__init__(self)
print "leave B"
>>> b = B() enter B
enter A
leave A
leave B
问题出现!
使用非绑定的类方法(用类名来引用的方法)来调用,并在参数列表中,引入待绑定的对象(self),从而达到调用父类的目的。
但是,问题来了!当父类发生变化时(如类B的父类由A变为C时),必须遍历整个类定义,把所有的通过非绑定的方法的类名全部替换过来。
class B(C): # A --> C
def __init__(self):
print "enter B"
C.__init__(self) # A --> C
print "leave B"
问题解决!-引入super
如果代码少,还改得过来,但是一旦代码上万行,就需要慢慢修改了。因此,自Python 2.2开始,Python添加了一个关键字super,来解决这个问题。下面是Python 2.3的官方文档说明:
super(type[, object-or-type])
Return the superclass of type. If the second argument is omitted the super object
returned is unbound. If the second argument is an object, isinstance(obj, type)
must be true. If the second argument is a type, issubclass(type2, type) must be
true. super() only works for new-style classes.
A typical use for calling a cooperative superclass method is:
class C(B):
def meth(self, arg):
super(C, self).meth(arg)
New in version 2.2.
所以,上面的代码我们可以改为如下:
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"
这样,就只要改继承的类名和基类的object两个地方。
用super的好处是,可以不用直接引用基类的名称就可以调用基类的方法。如果我们改变了基类的名称,那么所有子类的调用将不用改变。
二、新式类和老式类(经典类)区别
从上面可以看出,使用super是从2.2开始,且需要是新式类才支持。新式类和经典类区别如下:
- 新式类都从object继承,经典类不需要。
- 新式类的MRO(method resolution order 基类搜索顺序)算法采用C3算法广度优先搜索,而旧式类的MRO算法是采用深度优先搜索。
- 新式类相同父类只执行一次构造函数,经典类重复执行多次。
- 新式类的object基类是type类型,经典类的基类是classobj类型。
如下所示:
import inspect class A: #改为(object)为新式样类
def __init__(self):
print 'A'
print type(A) class B(A):
def __init__(self):
print 'B'
A.__init__(self) for x in inspect.getmro(B):
print dir(x)
b=B()
经典类结果为:
[root@zabbix src]# python tes4.py
['__doc__', '__init__', '__module__']
['__doc__', '__init__', '__module__']
B
A
<type 'classobj'>
新式类结果为:
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
B
A
<type 'type'>
三、老式方法(unbound方法)和super方法的差异
老式方法:
class A(object):
def __init__(self):
print "enter A"
print "leave A" class B(A):
def __init__(self):
print "enter B"
A.__init__(self)
print "leave B" class C(A):
def __init__(self):
print "enter C"
A.__init__(self)
print "leave C" class D(B,C):
def __init__(self):
print "enter D"
B.__init__(self)
C.__init__(self)
print "leave D"
结构如下:
>>> d=D()
enter D
enter B
enter A
leave A
leave B
enter C
enter A
leave A
leave C
leave D
super方法调用:
class A(object):
def __init__(self):
print "enter A"
print "leave A" class B(A):
def __init__(self):
print "enter B"
super(B,self).__init__()
print "leave B" class C(A):
def __init__(self):
print "enter C"
super(C,self).__init__()
print "leave C" class D(B,C):
def __init__(self):
print "enter D"
super(D,self).__init__()
print "leave D"
super方法结果如下:
>>> d=D()
enter D
enter B
enter C
enter A
leave A
leave C
leave B
leave D
从老式方法的结果可以发现, 这里面A的初始化函数被执行了两次. 因为我们同时要实现B和C的初始化函数, 所以分开调用两次, 这是必然的结果.
从super方法的结果会发现,所有父类ABC只执行了一次, 并不像之前那样执行了两次A的初始化.
然后, 又发现一个很奇怪的: 父类的执行是 BCA 的顺序并且是全进入后再统一出去. 这是MRO表问题
四、The Python 2.3 MRO(Method Resolution Order)
参考文章:https://www.python.org/download/releases/2.3/mro/
1. 如果是经典类MRO为DFS(深度优先搜索(子节点顺序:从下到上,从左到右))。
2. 如果是新式类MRO为BFS(广度优先搜索(子节点顺序:从下到上,从左到右))。
五、总结
1. super并不是一个函数,是一个类名,super(B, self)事实上返回是的一个super对象;
2. super(B, self).func的调用并不是用于调用当前类的父类的func函数;
3. Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数只调用一次(如果每个类都使用super,确保没A.func);
4.如果类被设计成使用了super,那么所有子类也必须要调用super,否则直接调用会出现重复调用的问题
5.super不是简单地调用基类的方法,而是调用MRO中的下一个类的方法
python的super函数学习的更多相关文章
- python之super()函数
python之super()函数 python的构造器奇特, 使用魔方. 构造器内对基类对象的初始化同样也很奇特, 奇特到没有半点优雅! 在构造器中使用super(class, instance)返回 ...
- 由Python的super()函数想到的
python-super *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !im ...
- Python中super函数的用法
之前看python文档的时候发现许多单继承类也用了super()来申明父类,那么这样做有何意义? 从python官网文档对于super的介绍来看,其作用为返回一个代理对象作为代表调用父类或亲类方法.( ...
- Python关于super()函数的理解
看下面的例子: class A: def __init__(self, name): self.name = name def bb(self): print('没事就爱瞎BB') class B(A ...
- python 中 super函数的使用
转载地址:http://python.jobbole.com/86787/ 1.简单的使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我 ...
- python 高阶函数学习, map、reduce
一个函数可以接收另一个函数作为参数,这样的函数叫做高阶函数. 函数map(): map()函数接收两个参数,一个是函数,一个是Iterable, map把函数作用于序列的每一个元素,并把结果作为Ite ...
- python中format函数学习笔记
简而言之,format函数就是用{}来代替之前的输出字符时使用的% print('my name is %s and I am %d years old' % ('porsche',23)) 下面详细 ...
- python中高阶函数学习笔记
什么是高阶函数 变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数 def fun(x, y, f): print f(x), f(y) fun ...
- python中super函数的参考
https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ http://wiki.jikexueyuan.com/proj ...
随机推荐
- 解决linux buffer/cache 消耗内存过高引发的问题
工作中接到DBA报障某台服务器 跑一些大的数据,服务器就无法远程连接,报错,抓过日志叫DELL工程师检测也没问题,系统也重装过, 现在些一些较大的数据就会报如 图错误,由于服务器远在异地城市IDC机房 ...
- print(dir(...)) 打印对象或者类中的方法和函数
- [T-ARA][Bo Peep Bo Peep]
歌词来源:http://music.163.com/#/song?id=22704468 作曲 : 新沙洞老虎/崔圭成 [作曲 : 新沙洞老虎/崔圭成] 作词 : 新沙洞老虎/崔圭成 [作词 : 新沙 ...
- wk_06.md
IO与文件操作 文件内建函数open 内建函数open提供了初始化输入/输出(I/O)操作的通用接口.open()内建函数成功打开文件后会返回一个文件对象.open函数的语法如下: open(file ...
- async/await actor promise 异步编程
Python协程:从yield/send到async/await http://blog.guoyb.com/2016/07/03/python-coroutine/ Async/Await替代Pro ...
- java集合---迭代器iterator
一:ArraryList 最终继承超级接口Collection,Colection接口继承Iterator接口. public interface Collection<E> exten ...
- iredmail 设置
一些问题和修改 1.收邮件很慢安装完毕后,测试会发现 发送邮件都是秒到,但收邮件特别慢 长达十几分钟,这是因为iredmail的灰名单规则导致的(需要外部邮箱进行3次投递才接收,防止垃圾邮件),禁用灰 ...
- FFmpeg中几个结构体的意义
AVCodec是存储编解码器信息的结构体,特指一个特定的解码器,比如H264编码器的名字,ID,支持的视频格式,支持的采样率等: AVCodecContext是一个描述编解码器采用的具体参数,比如采用 ...
- Angular动态表单生成(四)
ng-dynamic-forms实践篇(下) 我们接着上篇,先把小目标中的所有字段都定义出来 这部分就是苦力活儿了,把KendoUiComponent中的formModel完善即可: formMode ...
- json和jsonp的问题
本文转载自:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html 前言: 说到AJAX就会不可避免的面临 ...