python super的使用方法及实例详解


Posted in Python onSeptember 25, 2019

功能

super功能:super函数是子类用于调用父类(超类)的一个方法。

用法

1.在子类 __init__() 方法中正确的初始化父类,保证相同的基类只初始化一次。

2.覆盖特殊方法。

3.解决多重继承中,子类重复调用父类方法的问题。

注意

super()继承只能用于新式类,用于经典类时就会报错。

新式类:必须有继承的类,如果无继承的,则继承object

经典类:没有父类,如果此时调用super就会出现错误:『super() argument 1 must be type, not classobj)

在子类__init__()方法中正确初始化父类,保证相同的基类只初始化一次

假如说在父类中实现了一个方法,你想在子类中使用父类的这个方法并且做一定扩展但是又不想完全重写,并且这个场景中的继承属于多继承,那么super()就出场了,可以实现方法的增量修改。

A(父类)有x属性,B(子类)想添加y属性:

class A(object):
  def __init__(self,x):
    self.x = x
class B(A):
  def __init__(self,x,y):
    super(B,self,).__init__(x)
    self.y = y
a = A(2)
b = B(2,4)
print(a.x)
print(b.x,b.y)

覆盖Python特殊方法

class Proxy:
  def __init__(self, obj):
    self._obj = obj

  # Delegate attribute lookup to internal obj
  def __getattr__(self, name):
    return getattr(self._obj, name)

  # Delegate attribute assignment
  def __setattr__(self, name, value):
    if name.startswith('_'):
      super().__setattr__(name, value) # Call original __setattr__
    else:
      setattr(self._obj, name, value)

在上面代码中,__setattr__() 的实现包含一个名字检查。 如果某个属性名以下划线(_)开头,就通过 super() 调用原始的 __setattr__() , 否则的话就委派给内部的代理对象 self._obj 去处理。 这看上去有点意思,因为就算没有显式的指明某个类的父类, super() 仍然可以有效的工作。

解决多重继承中,子类重复调用父类方法的问题

class Base:
  def __init__(self):
    print('Base.__init__')
class A(Base):
  def __init__(self):
    Base.__init__(self)
    print('A.__init__')

尽管对于大部分代码而言这么做没什么问题,但是在更复杂的涉及到多继承的代码中就有可能导致很奇怪的问题发生。 比如,考虑如下的情况:

class Base:
  def __init__(self):
    print('Base.__init__')

class A(Base):
  def __init__(self):
    Base.__init__(self)
    print('A.__init__')

class B(Base):
  def __init__(self):
    Base.__init__(self)
    print('B.__init__')

class C(A,B):
  def __init__(self):
    A.__init__(self)
    B.__init__(self)
    print('C.__init__')

如果你运行这段代码就会发现 Base.__init__() 被调用两次,如下所示:

>>> c = C()
Base.__init__
A.__init__
Base.__init__
B.__init__
C.__init__
>>>

可能两次调用 Base.__init__() 没什么坏处,但有时候却不是。 另一方面,假设你在代码中换成使用 super() ,结果就很完美了:

class Base:
  def __init__(self):
    print('Base.__init__')
class A(Base):
  def __init__(self):
    super().__init__()
    print('A.__init__')

class B(Base):
  def __init__(self):
    super().__init__()
    print('B.__init__')

class C(A,B):
  def __init__(self):
    super().__init__() # Only one call to super() here
    print('C.__init__')

运行这个新版本后,你会发现每个 __init__() 方法只会被调用一次了:

>>> c = C()
Base.__init__
B.__init__
A.__init__
C.__init__
>>>

为了弄清它的原理,我们需要花点时间解释下Python是如何实现继承的。 对于你定义的每一个类,Python会计算出一个所谓的方法解析顺序(MRO)列表。 这个MRO列表就是一个简单的所有基类的线性顺序表。例如:

>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
<class '__main__.Base'>, <class 'object'>)
>>>

为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个MRO列表的构造是通过一个C3线性化算法来实现的。 我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

  • 子类会先于父类被检查
  • 多个父类会根据它们在列表中的顺序被检查
  • 如果对下一个类存在两个合法的选择,选择第一个父类

老实说,你所要知道的就是MRO列表中的类顺序会让你定义的任意类层级关系变得有意义。

当你使用 super() 函数时,Python会在MRO列表上继续搜索下一个类。 只要每个重定义的方法统一使用 super() 并只调用它一次, 那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次。 这也是为什么在第二个例子中你不会调用两次 Base.__init__() 的原因。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python开启多个子进程并行运行的方法
Apr 18 Python
python3.x 将byte转成字符串的方法
Jul 17 Python
Python实现删除排序数组中重复项的两种方法示例
Jan 31 Python
详解Python3 基本数据类型
Apr 19 Python
python实现websocket的客户端压力测试
Jun 25 Python
python requests库爬取豆瓣电视剧数据并保存到本地详解
Aug 10 Python
对Tensorflow中Device实例的生成和管理详解
Feb 04 Python
pandas中read_csv、rolling、expanding用法详解
Apr 21 Python
终于搞懂了Keras中multiloss的对应关系介绍
Jun 22 Python
Python pexpect模块及shell脚本except原理解析
Aug 03 Python
python利用platform模块获取系统信息
Oct 09 Python
Python 解决空列表.append() 输出为None的问题
May 23 Python
Pycharm+Python+PyQt5使用详解
Sep 25 #Python
利用python、tensorflow、opencv、pyqt5实现人脸实时签到系统
Sep 25 #Python
Python 3.6 中使用pdfminer解析pdf文件的实现
Sep 25 #Python
Python实现串口通信(pyserial)过程解析
Sep 25 #Python
Python根据服务获取端口号的方法
Sep 25 #Python
Python提取PDF内容的方法(文本、图像、线条等)
Sep 25 #Python
python使用 request 发送表单数据操作示例
Sep 25 #Python
You might like
收集的PHP中与数组相关的函数
2007/03/22 PHP
关于PHP中Object对象的笔记分享
2011/06/28 PHP
WordPress中访客登陆实现邮件提醒的PHP脚本实例分享
2015/12/14 PHP
PHP常用排序算法实例小结【基本排序,冒泡排序,快速排序,插入排序】
2017/02/07 PHP
php+Ajax无刷新验证用户名操作实例详解
2019/03/04 PHP
php使用curl伪造浏览器访问操作示例
2019/09/30 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
2020/02/23 PHP
一句话JavaScript表单验证代码
2009/08/02 Javascript
网页编辑器ckeditor和ckfinder配置步骤分享
2012/05/24 Javascript
jQuery选择器全集详解
2014/11/24 Javascript
解决node-webkit 不支持html5播放mp4视频的方法
2015/03/11 Javascript
js自定义QQ菜单效果
2017/01/10 Javascript
nodejs操作mongodb的填删改查模块的制作及引入实例
2018/01/02 NodeJs
vue watch自动检测数据变化实时渲染的方法
2018/01/16 Javascript
浅谈Vue.js之初始化el以及数据的绑定说明
2019/11/14 Javascript
[52:27]2018DOTA2亚洲邀请赛 3.31 小组赛B组 paiN vs Secret
2018/04/01 DOTA
[01:30:55]VG vs Mineski Supermajor 败者组 BO3 第三场 6.6
2018/06/07 DOTA
[45:50]完美世界DOTA2联赛PWL S3 CPG vs Forest 第二场 12.16
2020/12/17 DOTA
python中将阿拉伯数字转换成中文的实现代码
2011/05/19 Python
深入讲解Python中的迭代器和生成器
2015/10/26 Python
python daemon守护进程实现
2016/08/27 Python
python字符串,数值计算
2016/10/05 Python
5款非常棒的Python工具
2018/01/05 Python
python实现顺时针打印矩阵
2019/03/02 Python
pyqt5 实现在别的窗口弹出进度条
2019/06/18 Python
Django-rest-framework中过滤器的定制实例
2020/04/01 Python
Supersmart英国:欧洲市场首批食品补充剂供应商之一
2018/05/05 全球购物
美国价格实惠的在线眼镜网站:Zeelool
2020/12/25 全球购物
Unix里面如何在后台运行程序
2016/10/14 面试题
大学毕业生通用自荐信范文
2013/10/31 职场文书
财务部绩效考核方案
2014/05/04 职场文书
新农村建设汇报材料
2014/08/15 职场文书
教师三严三实心得体会
2014/10/11 职场文书
教师师德师风整改措施
2014/10/24 职场文书
CAD实训总结范文
2015/08/03 职场文书
思想品德课教学反思
2016/02/24 职场文书