python中super的使用
转自:http://python.jobbole.com/86787/
super() 的入门使用
在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现,比如:
def __init__(self, name):
self.name = name
def greet(self):
print 'Hello, I am %s.' % self.name
class Dog(Animal):
def greet(self):
super(Dog, self).greet() # Python3 可使用 super().greet()
print 'WangWang...'
|
1
2
3
4
5
6
7
8
9
10
|
class Animal(object):
def __init__(self, name):
self.name = name
def greet(self):
print 'Hello, I am %s.' % self.name
class Dog(Animal):
def greet(self):
super(Dog, self).greet() # Python3 可使用 super().greet()
print 'WangWang...'
|
在上面,Animal 是父类,Dog 是子类,我们在 Dog 类重定义了 greet 方法,为了能同时实现父类的功能,我们又调用了父类的方法,看下面的使用:
>>> dog.greet()
Hello, I am dog.
WangWang..
|
1
2
3
4
|
>>> dog = Dog('dog')
>>> dog.greet()
Hello, I am dog.
WangWang..
|
super 的一个最常见用法可以说是在子类中调用父类的初始化方法了,比如:
def __init__(self, a, b):
self.a = a
self.b = b
class A(Base):
def __init__(self, a, b, c):
super(A, self).__init__(a, b) # Python3 可使用 super().__init__(a, b)
self.c = c
|
1
2
3
4
5
6
7
8
9
|
class Base(object):
def __init__(self, a, b):
self.a = a
self.b = b
class A(Base):
def __init__(self, a, b, c):
super(A, self).__init__(a, b) # Python3 可使用 super().__init__(a, b)
self.c = c
|
深入 super()
看了上面的使用,你可能会觉得 super 的使用很简单,无非就是获取了父类,并调用父类的方法。其实,在上面的情况下,super 获得的类刚好是父类,但在其他情况就不一定了,super 其实和父类没有实质性的关联。
让我们看一个稍微复杂的例子,涉及到多重继承,代码如下:
def __init__(self):
print "enter Base"
print "leave Base"
class A(Base):
def __init__(self):
print "enter A"
super(A, self).__init__()
print "leave A"
class B(Base):
def __init__(self):
print "enter B"
super(B, self).__init__()
print "leave B"
class C(A, B):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class Base(object):
def __init__(self):
print "enter Base"
print "leave Base"
class A(Base):
def __init__(self):
print "enter A"
super(A, self).__init__()
print "leave A"
class B(Base):
def __init__(self):
print "enter B"
super(B, self).__init__()
print "leave B"
class C(A, B):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
|
其中,Base 是父类,A, B 继承自 Base, C 继承自 A, B,它们的继承关系如下:
/ \
/ \
A B
\ /
\ /
C
|
1
2
3
4
5
6
7
|
Base
/ \
/ \
A B
\ /
\ /
C
|
现在,让我们看一下使用:
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
|
1
2
3
4
5
6
7
8
9
|
>>> c = C()
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
|
如果你认为 super 代表『调用父类的方法』,那你很可能会疑惑为什么 enter A 的下一句不是 enter Base 而是 enter B。原因是,super 和父类没有实质性的关联,现在让我们搞清 super 是怎么运作的。
MRO 列表
事实上,对于你定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,它代表了类继承的顺序,我们可以使用下面的方式获得某个类的 MRO 列表:
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
|
1
2
|
>>> C.mro() # or C.__mro__ or C().__class__.mro()
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
|
那这个 MRO 列表的顺序是怎么定的呢,它是通过一个 C3 线性化算法来实现的,这里我们就不去深究这个算法了,感兴趣的读者可以自己去了解一下,总的来说,一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:
- 子类永远在父类前面
- 如果有多个父类,会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
super 原理
super 的工作原理如下:
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
|
1
2
3
|
def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
|
其中,cls 代表类,inst 代表实例,上面的代码做了两件事:
- 获取 inst 的 MRO 列表
- 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]
当你使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。
现在,让我们回到前面的例子。
首先看类 C 的 __init__ 方法:
|
1
|
super(C, self).__init__()
|
这里的 self 是当前 C 的实例,self.__class__.mro() 结果是:
|
1
|
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
|
可以看到,C 的下一个类是 A,于是,跳到了 A 的 __init__,这时会打印出 enter A,并执行下面一行代码:
|
1
|
super(A, self).__init__()
|
注意,这里的 self 也是当前 C 的实例,MRO 列表跟上面是一样的,搜索 A 在 MRO 中的下一个类,发现是 B,于是,跳到了 B 的 __init__,这时会打印出 enter B,而不是 enter Base。
整个过程还是比较清晰的,关键是要理解 super 的工作方式,而不是想当然地认为 super 调用了父类的方法。
小结
- 事实上,
super和父类没有实质性的关联。 super(cls, inst)获得的是 cls 在 inst 的 MRO 列表中的下一个类。
python中super的使用的更多相关文章
- python中super().__init__和类名.__init__的区别
super().__init__相对于类名.__init__,在单继承上用法基本无差 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次 多继承时 ...
- Python中super的用法【转载】
Python中super的用法[转载] 转载dxk_093812 最后发布于2019-02-17 20:12:18 阅读数 1143 收藏 展开 转载自 Python面向对象中super用法与MRO ...
- Python中super函数的用法
之前看python文档的时候发现许多单继承类也用了super()来申明父类,那么这样做有何意义? 从python官网文档对于super的介绍来看,其作用为返回一个代理对象作为代表调用父类或亲类方法.( ...
- python中super()的一些用法
在看python高级编程这本书的时候,在讲到super的时候,产生了一些疑惑,super在python中的用法跟其他的语言有一些不一样的地方,在网上找了一些资料,发现基本上很少有文章能把我的疑惑讲明白 ...
- python中super的理解(转)
原文地址:https://www.zhihu.com/question/20040039 针对你的问题,答案是可以,并没有区别.但是这题下的回答我感觉都不够好. 要谈论 super,首先我们应该无视 ...
- Python中super()的用法
参考链接:https://www.cnblogs.com/shengulong/p/7892266.html super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是 ...
- Python中super的应用
约定 单继承 多继承 super 是个类 多继承中 super 的工作方式 参考资料 约定 在开始之前我们来约定一下本文所使用的 Python 版本.默认用的是 Python 3,也就是说:本文所定义 ...
- Python中super详解
转至:https://mozillazg.com/2016/12/python-super-is-not-as-simple-as-you-thought.html 说到 super, 大家可能觉得很 ...
- python中super的使用方法
说白了,super的使用就是要子类要调用父类的方法,我们就用super,那你要有调用的规范,我们明白这个规范就可以了. 在python2和python3中,调用方法不同,注意就是了.Python3.x ...
随机推荐
- linux -- #!/bin/bash
#!/bin/bash是指此脚本使用/bin/bash来解释执行. 其中,#!是一个特殊的表示符,其后,跟着解释此脚本的shell路径. bash只是shell的一种,还有很多其它shell,如:sh ...
- Linux基础回想(1)——Linux系统概述
1. 什么是操作系统?它与硬件以及其它软件之间的关系是如何的? 操作系统是控制和管理计算机系统内各种硬件和软件资源.有效组织多道程序执行的系统软件(或程序集合),是用户和计算机之间的接口.详细的说: ...
- R语言低级绘图函数-grid
grid 函数用来在一张图表上添加网格线, 基本用法:默认在添加刻度线的地方添加网格线 plot(1:5, 1:5, xlim = c(0,6), ylim = c (0,6), type = &qu ...
- 桥接模式(bridge pattern)-------结构型模式
桥接模式是一种对象结构型模式,其将抽象部分和它的实现部分分离,使它们都可以独立的变化,又称为柄体(Handle and Body)模式或接口(Interface)模式. 优点: 1.分离抽象接口及其实 ...
- VC++ 打开文件或文件夹对话框的实现方法
实际工作开发中,由于各种应用,我们需要调用系统的打开文件对话框或者打开文件夹对话框,或两者兼有.特总结了常用的实现方法,仅供开发参考. 1. 打开文件对话框 常用的方法是使用系统的CFileDialo ...
- The Rox Java NIO Tutorial
FQ之后访问 http://rox-xmlrpc.sourceforge.net/niotut/
- tiny6410SDK制作NFS文件系统
1.初次编译内核出现问题 解决方法:将uboot的tools目录 下的mkimage拷贝到/bin/下. 2.开机后终端出现mmc0: error -110 whilst initialising S ...
- ios开发之--从相机或相册选取图片,并带删除操作的demo
多选图片的一个效果,如下图:
- swift学习笔记之--类的计算属性
1,Swift中类可以使用计算属性,即使用get和set来间接获取/改变其他属性的值,代码如下 class Calcuator{ ; ; var sum:Int{ get{ return a + b ...
- kafka的相关操作脚本
总结最近用到的kafka相关命令和脚本. 1.创建Topic./kafka-topics.sh --zookeeper cc13-141:2182 --topic mytopic --replicat ...