面向对象super内置函数(转)
super函数用来解决钻石继承。
一、python的继承以及调用父类成员
父类:
class Base(object):
def __init__(self):
print("base init.")
普通方法调用父类:
class Leaf(Base):
def __init__(self):
Base.__init__(self)
print("Leaf init.")
super方法调用父类:
class Leaf(Base):
def __init__(self):
super(Leaf, self).__init__()
print("Leaf init.")
二、钻石继承

使用普通方法调用父类,base类会初始化2次。用super解决这个问题。

class Base(object):
def __init__(self):
print("Base init")
class Medium1(Base):
def __init__(self):
super(Medium1, self).__init__()
print("Medium1 init")
class Medium2(Base):
def __init__(self):
super(Medium2, self).__init__()
print("Medium2 init")
class Leaf(Medium1, Medium2):
def __init__(self):
super(Leaf, self).__init__()
print("Leaf init")
leaf = Leaf()

三、super工作原理
要理解super的原理,就要先了解mro。mro是method resolution order的缩写,表示了类继承体系中的成员解析顺序。在python中,每个类都有一个mro的类方法。我们来看一下钻石继承中,Leaf类的mro是什么样子的:
print(Leaf.mro())
[<class '__main__.Leaf'>, <class '__main__.Medium1'>, <class '__main__.Medium2'>, <class '__main__.Base'>, <class 'object'>]
可以看到mro方法返回的是一个祖先类的列表。Leaf的每个祖先都在其中出现一次,这也是super在父类中查找成员的顺序。
通过mro,python巧妙地将多继承的图结构,转变为list的顺序结构。super在继承体系中向上的查找过程,变成了在mro中向右的线性查找过程,任何类都只会被处理一次。
通过这个方法,python解决了多继承中的2大难题:
1. 查找顺序问题。从Leaf的mro顺序可以看出,如果Leaf类通过super来访问父类成员,那么Medium1的成员会在Medium2之前被首先访问到。如果Medium1和Medium2都没有找到,最后再到Base中查找。
2. 钻石继承的多次初始化问题。在mro的list中,Base类只出现了一次。事实上任何类都只会在mro list中出现一次。这就确保了super向上调用的过程中,任何祖先类的方法都只会被执行一次。
四、super的使用方法
用法一、super(type, obj)
当我们在Leaf的__init__中写这样的super时:
class Medium1(Base):
def __init__(self):
super(Medium1, self).__init__()
print("Medium1 init")
super(Leaf, self).__init__()的意思是说:
- 获取self所属类的mro, 也就是[Leaf, Medium1, Medium2, Base]
- 从mro中Leaf右边的一个类开始,依次寻找__init__函数。这里是从Medium1开始寻找
- 一旦找到,就把找到的__init__函数绑定到self对象,并返回
从这个执行流程可以看到,如果我们不想调用Medium1的__init__,而想要调用Medium2的__init__,那么super应该写成:super(Medium1, self)__init__()
用法二、super(type, type2)
class Leaf(Medium1, Medium2):
def __new__(cls):
obj = super(Leaf, cls).__new__(cls)
print("Leaf new")
return obj
super(Leaf, cls).__new__(cls)的意思是说:
- 获取cls这个类的mro,这里也是[Leaf, Medium1, Medium2, Base]
- 从mro中Leaf右边的一个类开始,依次寻找__new__函数
- 一旦找到,就返回“ 非绑定 ”的__new__函数
由于返回的是非绑定的函数对象,因此调用时不能省略函数的第一个参数。这也是这里调用__new__时,需要传入参数cls的原因,同样的,如果我们想从某个mro的某个位置开始查找,只需要修改super的第一个参数就行。
面向对象super内置函数(转)的更多相关文章
- 面向对象编程之super内置函数的用法
先来看一段代码: 定义一个名叫People的父类,又定义了一个叫Teacher的老师类和一个叫Student的学生类 来继承People的类,并根据这两个子类实例化出两个对象s1和t1. class ...
- 面向对象进阶------>内置函数 str repr new call 方法
__new__方法: 我们来讲个非常非常重要的内置函数和init一样重要__new__其实在实例话对象的开始 是先继承父类中的new方法再执行init的 就好比你生孩子 先要把孩子生出来才能对孩子 ...
- 面向对象_内置函数 property
property 将方法伪装成为属性,可以不用加上()就可以调出其属性. 但是用__dict__,不能调出此属性 from math import pi class Circle: def __ini ...
- 组合&反射&面向对象内置函数
内容概要 组合 反射 面向对象的内置函数 异常 内容详细 一.组合 组合:在对象中定义一个属性,属性的值是另一个对象 除了继承父类的方法,这是获取另一个类中属性的另一种方式 如果想给学生对象添加课程属 ...
- Python 面向对象 (补充) , 反射 , 内置函数
面向对象中内置函数 issubclass方法: 检查第一个参数是否是第二个参数的子子孙孙类 返回 : 是一个布尔值 class Base(object): pass class Foo( ...
- python内置函数详细介绍
知识内容: 1.python内置函数简介 2.python内置函数详细介绍 一.python内置函数简介 python中有很多内置函数,实现了一些基本功能,内置函数的官方介绍文档: https: ...
- python--表达式形式的yield、面向过程编程、内置函数
yield的表达式形式 def init(func): def wrapper(*args, **kwargs): g = func(*args, **kwargs) next(g) return g ...
- day28 面向对象:反射,内置函数,类的内置方法
面向对象进阶博客地址链接: http://www.cnblogs.com/Eva-J/articles/7351812.html 复习昨日内容: # 包 # 开发规范 # # hashlib # 登录 ...
- python笔记4 内置函数,匿名函数.递归函数 面向对象(基础, 组合,继承)
内置函数 eval和exec eval :执行字符串中的代码并将结果返回给执行者,有返回值 exec:执行字符串中的代码,往往用于执行流程语句,没有返回值. s1 = '1+2' s2 = 'prin ...
随机推荐
- JAVA THINGKING (一)
保存数据位置: (1) 寄存器.这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部. (2) 堆栈.驻留于常规RAM(随机访问存储器)区域,这是一种特别快.特别有效的数据保存方式, ...
- 转:CURL库在程序中的运用浅析
CURL库在程序中的运用浅析-nk_ysg-ChinaUnix博客 http://blog.chinaunix.net/uid-22476414-id-3286638.html 这个目录的文章转载fr ...
- dcos下rexray服务的配置
在dcos环境下,rexray服务的默认配置文件为/opt/mesosphere/etc/rexray.conf,而其服务文件则是 /etc/systemd/system/dcos-rexray.se ...
- 如何在ubuntu下使用windows下的程序(eg: .exe)
为了在ubutu下安装百度云管家,上网查了下如何在ubuntu 下安装.exe文件,其中遇到一些问题记录如下: 使用的命令: 开始时直接使用的sudo apt-get install wine 在运行 ...
- 洛谷 - P3033 - 牛的障碍Cow Steeplechase - 二分图最大独立集
https://www.luogu.org/fe/problem/P3033 二分图最大独立集 注意输入的时候控制x1,y1,x2,y2的相对大小. #include<bits/stdc++.h ...
- 51nod 1278【贪心】
主要这道题没有包含的情况,所以直接搞个左端,然后对于每个二分求一下>right的最近的位置j,那么ans就会增加 j 以后的: #include <cstdio> #include ...
- laravel 布局 详解(实例)
在resources/views里创建layouts,并在layouts里创建app.blade.php, 这个php文件放的就是你的页面框架,也就是多页面公用的内容,如下 <!DOCTYPE ...
- 3DMAX 烘培技术
烘培是指,把光照信息渲染成贴图,而后把这个烘培后的贴图再贴回到场景中去的技术.烘培技术把光照计算的结果提前写入到了贴图中,因此在实时渲染中不需要进行耗时的光照计算,大大提高了实时渲染的效率. 烘培和渲 ...
- PyCharm的一些使用技巧
定位到函数定义 在函数名处 Ctrl + B 就会快速定位到函数定义处 在Console中执行文件 全选内容后,右键菜单 Execute Selection in Console 或者快捷键 Alt ...
- 洛谷P3960 列队(Splay)
传送门 感觉自己好久不打数据结构已经完全不会了orz…… 据说正解树状数组?然而并不会 首先考虑一下每一次操作,就是把一个人从这一行中取出并放到行的最后,再从最后一列取出放到列的最后 那么这两种操作其 ...