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 ...
随机推荐
- django新建项目,连接mysql数据库
安装django,进入Django目录,运行 python setup.py install 在workplace目录下新建一个名为site01的项目: cd workplacedjango-admi ...
- Java 系统学习梳理_【All】
Java基础 1. Java学习---JDK的安装和配置 2. Java学习---Java代码编写规范 2. Java学习---HashMap和HashSet的内部工作机制 3. Java学习---J ...
- MySQL 索引的介绍与应用
Mysql索引 一. mysql 索引 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息. 二:MySQL索引类型 按存储结构区分:聚集索引(又称聚类索引,簇 ...
- php请求页面将返回的页面发送email
<?php require_once 'CLI_config.php'; require_once dirname(__FILE__).'/../../../../common/framewor ...
- HTML5 JS 实现浏览器全屏(F11的效果)
项目中有需要使用JS来控制浏览器全屏的方法 DEMO地址: http://zhongxia245.github.io/demo/js2fullpanel.html function fullScree ...
- Zepto的SwipeUp 在 android 和微信 的解决方案
Zepto的SwipeUp 在 android 和微信 的解决方案 时间:2016-04-19 22:20:09 作者:zhongxia 问题解决方案: Q:为什么swipeUp和swipeDown在 ...
- #001 Emmet的API图片
这个是一张Emmet的快捷键图片,里面包含了所有的快捷键. 虽然有很多的快捷键,但是常用的也就那么几个 . 样式 # ID > 上下级节点 + .col-md-8+.col-md- ...
- Oracle 空间查询, 数据类型为 sdo_geometry
因网上搜索到的相关资料大部分都是关于sdo_geometry的介绍和以及通过sql语句添加要素,查询要素等等.没有找到存储过程相关的例子,所以只好自己动手啦. 准备 环境:windowsxp系统,安装 ...
- ubuntu16.04更新内核--使用4.6以上的内核会让用A卡的Dell电脑更快--及卸载多余内核
tips:我自己就是Dell的A卡电脑,用16.04桌面感觉不如fedora流畅,后来手动升级到4.6.2内核,发现可以和fedora与windows一般桌面操作流畅度. 我试过了4.7的开发版内核, ...
- HBase学习之路 (二)HBase集群安装
前提 1.HBase 依赖于 HDFS 做底层的数据存储 2.HBase 依赖于 MapReduce 做数据计算 3.HBase 依赖于 ZooKeeper 做服务协调 4.HBase源码是java编 ...