Python内置函数(30)——super
英文文档:
super([type[, object-or-type]])
Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.
The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super(). The attribute is dynamic and can change whenever the inheritance hierarchy is updated.
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 (this is useful for classmethods).
There are two typical use cases for super. In a class hierarchy with single inheritance, super can be used to refer to parent classes without naming them explicitly, thus making the code more maintainable. This use closely parallels the use of super in other programming languages.
The second use case is to support cooperative multiple inheritance in a dynamic execution environment. This use case is unique to Python and is not found in statically compiled languages or languages that only support single inheritance. This makes it possible to implement “diamond diagrams” where multiple base classes implement the same method. Good design dictates that this method have the same calling signature in every case (because the order of calls is determined at runtime, because that order adapts to changes in the class hierarchy, and because that order can include sibling classes that are unknown prior to runtime).
Note that super() is implemented as part of the binding process for explicit dotted attribute lookups such as super().__getitem__(name). It does so by implementing its own __getattribute__() method for searching classes in a predictable order that supports cooperative multiple inheritance. Accordingly, super() is undefined for implicit lookups using statements or operators such as super()[name].
Also note that, aside from the zero argument form, super() is not limited to use inside methods. The two argument form specifies the arguments exactly and makes the appropriate references. The zero argument form only works inside a class definition, as the compiler fills in the necessary details to correctly retrieve the class being defined, as well as accessing the current instance for ordinary methods.
根据传入的参数生成一个新的子类和父类关系的代理对象
说明:
1. super函数返回的是一个代理对象,通过此对象可以调用所在类的父类或者兄弟类的方法,而不显示的指定父类或者兄弟类的类名。
2. 为什么要有super?
最早之前,在子类(B)中调用父类(A)的方法采用的方式如下:
#定义父类A
>>> class A(object):
def __init__(self):
print('A.__init__') #实例化A
>>> a = A()
A.__init__ # 定义子类B,继承A,在B的__init__ 方法中调用A的__init__方法
>>> class B(A):
def __init__(self):
print('B.__init__')
A.__init__(self) #实例化B
>>> b = B()
B.__init__
A.__init__
假设现在要更改新定义一个类(A1),并更改继承关系(B->A改成B->A1),则需要所有类中做如下修改:
#定义新的父类A1
>>> class A1(object):
def __init__(self):
print('A1.__init__') #更改继承关系B->A改成B->A1
>>> class B(A1):
def __init__(self):
print('B.__init__')
A1.__init__(self) #能正确调用新的父类A1的__init__方法
>>> b = B()
B.__init__
A1.__init__ #假设忘了修改A.__init__(self)
>>> class B(A1):
def __init__(self):
print('B.__init__')
A.__init__(self) #则还是调用了A的__init__方法
>>> b = B()
B.__init__
A.__init__
引入super之后,不需要显示指定父类的类名,增强了程序的可维护性:
#B->A 改用super方式调用父类方法
>>> class B(A):
def __init__(self):
print('B.__init__')
super().__init__() #能正确调用父类方法
>>> b = B()
B.__init__
A.__init__ #更改继承关系B->A改成B->A1,调用父类方法方式不用修改
>>> class B(A1):
def __init__(self):
print('B.__init__')
super().__init__() #也能正确调用父类方法
>>> b = B()
B.__init__
A1.__init__
3. 不带任何参数的super等效于super(类名,self),此种情况多用于单继承关系的子类中。
#super不带参数
>>> class B(A1):
def __init__(self):
print('B.__init__')
super().__init__() #能正确调用父类方法
>>> b = B()
B.__init__
A1.__init__ #super带两个参数(类名,self)
>>> class B(A1):
def __init__(self):
print('B.__init__')
super(B,self).__init__() #也能正确调用父类方法
>>> b = B()
B.__init__
A1.__init__
4. 如果第2个参数不传入,则表示代理对象不绑定继承关系。
#super第2个参数不传入,生成代理对象不绑定继承关系
>>> class B(A1):
def __init__(self):
print('B.__init__')
super(B).__init__() #super(B).__init__()方法执行时不会调用父类方法
>>> b = B()
B.__init__
5. 如果第2个参数是一个对象,则对象必须是第1个参数指定类型的实例,此种关系多用于多层继承关系的子类中。
#定义父类A
>>> class A(object):
def __init__(self):
print('A.__init__') #定义子类B,继承A,__init__中调用父类的__init__方法
>>> class B(A):
def __init__(self):
print('B.__init__')
super().__init__() #定义子类C,继承B,__init__中调用父类的__init__方法
>>> class C(B):
def __init__(self):
print('C.__init__')
super().__init__() #实例化C时,执行C的__init__方法,调用直接父类B的__init__方法,又进一步调用间接父类A的__init__方法
>>> c = C()
C.__init__
B.__init__
A.__init__ #重新定义子类C,继承关系不变,调用父类方法__init__时改用super(B,self)
>>> class C(B):
def __init__(self):
print('C.__init__')
super(B,self).__init__() #实例化C时,执行C的__init__方法,super(B,self)代理找到B的父类A,将self转换成B的实例,直接调用了A的__init__方法,跳过了调用B的__init__方法
>>> c = C()
C.__init__
A.__init__ #定义一个新类D
>>> class D(object):
def __init__(self):
print('D.__init__') #重新定义C,继承关系不变,调用父类方法__init__时改用super(D,self)
>>> class C(B):
def __init__(self):
print('C.__init__')
super(D,self).__init__() #实例化C时,执行C的__init__方法,super(D,self)代理找到D的父类object,将self转换成D的实例,因为D和C无继承关系,self
无法转换成D的实例所以报错
>>> c= C()
C.__init__
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
c= C()
File "<pyshell#13>", line 4, in __init__
super(D,self).__init__()
TypeError: super(type, obj): obj must be an instance or subtype of type
6. 如果第2个参数时一个类型,则类型必须是第1个参数指定类型的子类,此种关系多用于多层继承关系的子类中,适用于类方法。
#定义父类A,并定义有一个类方法sayHello
>>> class A(object):
@classmethod
def sayHello(cls):
print('A.sayHello') # 定义子类B,继承A,重写类方法sayHello,在其中调用父类的sayHello方法
>>> class B(A):
@classmethod
def sayHello(cls):
print('B.sayHello')
super().sayHello() # 定义子类C,继承B,重写类方法sayHello,在其中调用父类的sayHello方法
>>> class C(B):
@classmethod
def sayHello(cls):
print('C.sayHello')
super().sayHello() #调用C的类方法sayHello,其调用C的直接父类B的类方法sayHello,调用时B的sayHello方法又调用B的直接父类A的类方法sayHello
>>> C.sayHello()
C.sayHello
B.sayHello
A.sayHello #重新定义类C,继承关系不变,使用super(C,C)的方式调用父类方法
>>> class C(B):
@classmethod
def sayHello(cls):
print('C.sayHello')
super(C,C).sayHello() #调用C的类方法sayHello,super(C,C)代理对象,找到C的直接父类B,然后调用C的直接父类B的类方法sayHello,调用时B的sayHello方法又调用B的直接父类A的类方法sayHello
>>> C.sayHello()
C.sayHello
B.sayHello
A.sayHello #重新定义类C,继承关系不变,使用super(B,C)的方式调用父类方法
>>> class C(B):
@classmethod
def sayHello(cls):
print('C.sayHello')
super(B,C).sayHello() #调用C的类方法sayHello,super(B,C)代理对象,找到B的直接父类A,然后调用B的直接父类A的类方法sayHello,中间不会调用B的sayHello方法
>>> C.sayHello()
C.sayHello
A.sayHello #定义一个新类D,和A、B、C无继承关系
>>> class D(object):
@classmethod
def sayHello(cls):
print('D.sayHello') #重新定义类C,继承关系不变,使用super(D,C)的方式调用父类方法
>>> class C(B):
@classmethod
def sayHello(cls):
print('C.sayHello')
super(D,C).sayHello() #调用C的类方法sayHello,super(D,C)代理对象,找到B的直接父类object,然后将C转换成D类,转换失败调用出错
>>> C.sayHello()
C.sayHello
Traceback (most recent call last):
File "<pyshell#81>", line 1, in <module>
C.sayHello()
File "<pyshell#80>", line 5, in sayHello
super(D,C).sayHello()
TypeError: super(type, obj): obj must be an instance or subtype of type
Python内置函数(30)——super的更多相关文章
- Python内置函数(63)——super
英文文档: super([type[, object-or-type]]) Return a proxy object that delegates method calls to a parent ...
- Python内置函数(30)——hex
英文文档: hex(x) Convert an integer number to a lowercase hexadecimal string prefixed with “0x”, for exa ...
- Python内置函数之super()
super(type[,object-or-type]) super()的作用在于类继承方面. 他可以实现不更改类内部代码,但是改变类的父类. 例子: 一般我们继承类的方式: >>> ...
- Python内置函数和内置常量
Python内置函数 1.abs(x) 返回一个数的绝对值.实参可以是整数或浮点数.如果实参是一个复数,返回它的模. 2.all(iterable) 如果 iterable 的所有元素为真(或迭代器为 ...
- Python | 内置函数(BIF)
Python内置函数 | V3.9.1 | 共计155个 还没学完, 还没记录完, 不知道自己能不能坚持记录下去 1.ArithmeticError 2.AssertionError 3.Attrib ...
- python内置函数
python内置函数 官方文档:点击 在这里我只列举一些常见的内置函数用法 1.abs()[求数字的绝对值] >>> abs(-13) 13 2.all() 判断所有集合元素都为真的 ...
- Python 内置函数笔记
其中有几个方法没怎么用过, 所以没整理到 Python内置函数 abs(a) 返回a的绝对值.该参数可以是整数或浮点数.如果参数是一个复数,则返回其大小 all(a) 如果元组.列表里面的所有元素都非 ...
- 【转】python 内置函数总结(大部分)
[转]python 内置函数总结(大部分) python 内置函数大讲堂 python全栈开发,内置函数 1. 内置函数 python的内置函数截止到python版本3.6.2,现在python一共为 ...
- python内置函数,匿名函数
一.匿名函数 匿名函数:为了解决那些功能很简单的需求而设计的一句话函数 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc = lambda n ...
随机推荐
- css学习の第一四弹—代码格式简写归纳
一.代码简写方式归纳 >>1.盒模型代码简写: 外边距(margin).内边距(padding)和边框(border)设置上下左右四个方向的边距是按照顺时针方向设置的:上右下左 1.如果t ...
- [转]What is a WebRTC Gateway anyway? (Lorenzo Miniero)
[转]What is a WebRTC Gateway anyway? (Lorenzo Miniero) https://webrtchacks.com/webrtc-gw/ As I mentio ...
- QT 中setUserData和setProperty问题
在5.9的官方文档里是找不到QObject中的setUserData 的,相反他提供了setProperty(). void setUserData(uint id, QObjectUserData ...
- .msi安装包安装方法(安装错误2503和2502)
把鼠标放到Win8屏幕的最左下角,等待Win8 Metro界面的缩略图出现后点击鼠标右键,在弹出的菜单中选择“命令提示符(管理员)”在“命令提示符(管理员)”中输入 msiexec /package ...
- Throwable.异常
异常: 在运行期间发生的不正常情况. 在JAVA中用类的形式对异常的情况进行了类的封装. 这些描述不正常情况的类就称为异常类. 异常类就是java通过面向对象的思想将问题封装成了对象.用异常类对问题进 ...
- web 直播&礼物赠送------腾讯云(四)
直播项目搁置了将近1年,以为都搁浅了,没想到头头又提起来了,这次直播技术更替为了腾讯云,消息系统没变,采用的依然是融云,新增了礼物赠送功能. 项目完成基本就是这样子: 一,播放器 由阿里云转腾讯云,w ...
- 关于SQL性能优化的十条经验
1.查询的模糊匹配 尽量避免在一个复杂查询里面使用 LIKE '%parm1%'—— 红色标识位置的百分号会导致相关列的索引无法使用,最好不要用. 解决办法: 其实只需要对该脚本略做改进,查询速度便会 ...
- 《Linux命令行与shell脚本编程大全》- 读书笔记2 - 更多的bash shell命令
更多的bash shell命令 想检测进程,需要熟悉ps命令的用法.ps命令好比工具中的瑞士军刀,它能输出运行在系统上的所有程序的许多信息.默认情况下,ps命令只会显示运行在当前控制台下的属于当前用户 ...
- Angular开发实践(四):组件之间的交互
在Angular应用开发中,组件可以说是随处可见的.本篇文章将介绍几种常见的组件通讯场景,也就是让两个或多个组件之间交互的方法. 根据数据的传递方向,分为父组件向子组件传递.子组件向父组件传递及通过服 ...
- 笔记:MyBatis XML配置-typeHandlers 默认类型处理器
类型处理器 Java 类型 JDBC 类型 BooleanTypeHandler java.lang.Boolean, boolean 数据库兼容的 BOOLEAN ByteTypeHandler j ...