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 ...
随机推荐
- SOA面向服务架构——SOA的概念
SOA的概念是Gartner 在1996年提出来的,并于2002年12月进一步提出SOA是“现代应用开发领域最重要的课题”. 一.SOA的定义 SOA分为广义的SOA和狭义的SOA,广义的SOA是 ...
- 关于print缩不缩进%有else没else的影响
关于print缩不缩进%有else没else的影响 if gender == "男": # = 赋值. == 判断print("上厕所")else: print ...
- if a in range(len(lst)): print(a,lst[a]) #获取索引和对应元素, 背下来~~
经典的"获取元素的索引和元素", 背下来! if a in range(len(lst)): print(a, lst[a])
- 我在德国做SAP CRM One Order redesign工作的心得
时间过得很快,今天是我到德国工作的第四周,刚好一个月.Prototype的框架已经搭起来了,现在Order能够在新的框架下正常读写,能跑一些简单的scenario,这些scenario对于end us ...
- mybatis中使用in查询时的注意事项
1. 当查询的参数只有一个时 findByIds(List<Long> ids) 1.a 如果参数的类型是List, 则在使用时,collection属性要必须指定为 list < ...
- javascript库概念与连缀
一.JavaScript 库 1.什么是javascript库: javascript库,说白了,就是把各种常用的代码片段,组织起来放在一个 js 文件里,组成一个包,这个包就是 JavaScript ...
- vim高级操作命令
1.首先在命令模式下,输入“:set nu”显示行号:通过行号确定你要删除的行:命令输入“:32,65d”,回车键,32-65行就被删除了,很快捷吧如果无意中删除错了,可以使用‘u’键恢复(命令模式下 ...
- BZOJ2281:[SDOI2011]黑白棋(博弈论,组合数学,DP)
Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小 ...
- BZOJ2806:[CTSC2012]Cheat(广义SAM,二分,DP)
Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数 接下来M行的01串,表示标准作文库 接下来N行的01串,表示N篇作文 Output N行,每行一 ...
- centos安装swoole
编译安装swoole: cd && wget https://github.com/swoole/swoole-src/archive/1.8.6-stable.tar.gz ...