python中的super用法详解_Python中super函数用法实例分析

本文实例讲述了python中super函数用法。分享给大家供大家参考,具体如下:

这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简单说, super函数是调用下一个父类(超类)并返回该父类实例的方法. 这里的下一个的概念参考后面的MRO表介绍.

help介绍如下:

super(type, obj) -> bound super object; requires isinstance(obj, type)

super(type) -> unbound super object

super(type, type2) -> bound super object; requires issubclass(type2, type)

Typical use to call a cooperative superclass method:

class C(B):

def meth(self, arg):

super(C, self).meth(arg)

由此可知, super有三种用法, 第一参数总是召唤父类的那个类, 第二参数可缺(返回非绑定父类对象),也可以是实例对象或该类的子类. 最终返回的都是父类的实例(绑定或非绑定). 在Python3中,super函数多了一种用法是直接super(),相当于super(type,首参), 这个首参就是一般的传入的self实例本身啦. 因为在py2里面常用也是这种写法.

另外, 在py2中, super只支持新类( new-style class, 就是继承自object的).

为什么要调用父类?

在类继承时, 要是重定义某个方法, 这个方法就会覆盖掉父类的相应同名方法. 通过调用父类实例, 可以在子类中同时实现父类的功能.例如: # Should be new-class based on object in python2.

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"

>>> b = B()

enter B

enter A

leave A

leave B

通过调用super获得父类实例从而可以实现该实例的初始化函数. 这在实践中太常用了 (因为要继承父类的功能, 又要有新的功能).

直接使用父类来调用的差异

事实上, 上面的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"

通过直接使用父类类名来调用父类的方法, 实际也是可行的. 起码在上面的例子中效果上他们现在是一样的. 这种方法在老式类中也是唯一的调用父类的方法 (老式类没有super).

通过父类类名调用方法很常用, 比较直观. 但其效果和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

可以发现, 这里面A的初始化函数被执行了两次. 因为我们同时要实现B和C的初始化函数, 所以分开调用两次, 这是必然的结果.

但如果改写成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"

>>> d=D()

enter D

enter B

enter C

enter A

leave A

leave C

leave B

leave D

会发现所有父类ABC只执行了一次, 并不像之前那样执行了两次A的初始化.

然后, 又发现一个很奇怪的: 父类的执行是 BCA 的顺序并且是全进入后再统一出去. 这是MRO表问题, 后面继续讨论.

如果没有多继承, super其实和通过父类来调用方法差不多. 但, super还有个好处: 当B继承自A, 写成了A.__init__, 如果根据需要进行重构全部要改成继承自 E,那么全部都得改一次! 这样很麻烦而且容易出错! 而使用super()就不用一个一个改了(只需类定义中改一改就好了)

Anyway, 可以发现, super并不是那么简单.

MRO 表

MRO是什么? 可以通过以下方式调出来: >>> D.mro() # or d.__class__.mro() or D.__class__.mro(D)

[D, B, C, A, object]

>>> B.mro()

[B, A, object]

>>> help(D.mro)

#Docstring:

#mro() -> list

#return a type's method resolution order

#Type: method_descriptor

MRO就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表 (类继承顺序表去理解也行) 啦.

这个表有啥用? 首先了解实际super做了啥: def super(cls, inst):

mro = inst.__class__.mro()

return mro[mro.index(cls) + 1]

换而言之, super方法实际是调用了cls的在MRO表中的下一个类. 如果是简单一条线的单继承, 那就是父类->父类一个一个地下去罗. 但对于多继承, 就要遵循MRO表中的顺序了. 以上面的D的调用为例:

d的初始化

-> D (进入D) super(D,self)

-> 父类B (进入B) super(B,self)

-> 父类C (进入C) super(C,self)

-> 父父类A (进入A) (退出A) # 如有继续super(A,self) -> object (停了)

-> (退出C)

-> (退出B)

-> (退出D)

所以, 在MRO表中的超类初始化函数只执行了一次!

那么, MRO的顺序究竟是怎么定的呢? 这个可以参考官方说明The Python 2.3 Method Resolution Order . 基本就是, 计算出每个类(从父类到子类的顺序)的MRO, 再merge 成一条线. 遵循以下规则:

在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。 这个原则包括两点:

1. 基类永远在派生类后面

2. 类定义时的继承顺序影响相对顺序.

如果有以下继承 (Python中的super用法详解):

object

/ \

/ A

| / \

B-1 C-2 D-2

\ / /

E-1 /

\ /

F

那么MRO是: F -> E -> B -> C -> D -> A -> object

怎么解释呢?

根据官方的方法, 是: L(O) = O

L(B) = B O

L(A) = A O

L(C) = C A O

L(D) = D A O

L(E) = E + merge(L(B),L(C))

= E + merge(BO,CAO)

= E + B + merge(O,CAO)

= E + B + C + merge(O,AO)

= E + B + C + A + merge(O,O)

= E B C A O

L(F) = F + merge(L(E),L(D))

= F + merge(EBCAO,DAO)

= F + EBC + merge(AO,DAO)

= F + EBC + D + merge(AO,AO)

= F EBC D AO

看起来很复杂..但还是遵循在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。所以, 我个人认为可以这么想: 先找出最长深度最深的继承路线F->E->C->A->object. (因为必然基类永远出现在派生类后面) 类似深度优先, 定出其余顺序: F->E->B->obj, F->D->A-object 如果有多个基类,基类的相对顺序保持不变, 类似于merge时优先提前面的项. 所以排好这些路线: (FEBO, FECAO, FDAO) F->E->B->obj且E(B,C)决定B在C前面.所以F->E->B->C->A->obj(相当于F+merge(EBO,ECAO)). F->D->A-object且F(E,D)决定了D在E后, 所以D在E后A前. 因为相对顺序, 相当于FE+merge(BCAO, DAO), 所以FE BC D AO

更多可参考 Raymond Hettinger 的Python's super() considered super! (据说很经典的讨论) James Knight 的 Python's Super Considered Harmful Py3 cookbook: 8.7 调用父类方法http://python3-cookbook.readthedocs.org/zh_CN/latest/c08/p07_calling_method_on_parent_class.html Python编程中对super函数的正确理解和用法解析

关于Python相关内容感兴趣的读者可查看本站专题:《Python面向对象程序设计入门与进阶教程》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python编码操作技巧总结》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 管理多个进程_管理多个Java安装

java 管理多个进程随着越来越多的Java版本发布,在本地环境中管理多个Java安装将变得更加有趣。 不同的项目可能需要不同的Java版本。 jenv项目是管理Java安装的便捷方法。 它可以在全局,目录和外壳程序级别上设置本地Java安装,并使用易于记忆…

NP-完全性介绍

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 旨在 理解 “NP-完全性” 的idea &#xff1b; 【1】难与易 1.1&#xff09;不可判定问题&#xff1a;正如实数不足以表示 x^2 < 0 的解那样&#xff0c;可以证明&#xff0c; 计算机不可能解决碰…

python发邮件给多个人发送消息_python发送邮件(带附件)、发送给多人、抄送给多人的示例...

python发送邮件(带附件)、发送给多人、抄送给多人的示例#!/usr/bin/env python# -*-encoding: utf-8 -*-import smtplibfrom email.mime.multipart import MIMEMultipartfrom email.mime.text import MIMEText#image包可以发送图片形式的附件# from email.mime.image import MI…

camel apache_Apache Camel 3只有2个月的路程

camel apache骆驼队正忙于为 Apache Camel 3.今天&#xff0c;第二个候选版本已构建并发布在暂存库中&#xff0c;供早期的适配器尝试 。 当我自己很忙的时候&#xff0c;我只想写一篇简短的博客文章&#xff0c;以使社区了解Apache Camel 3即将发布&#xff0c;并且我们希望…

浅谈java代理

【0】README 0.1&#xff09; 本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理解 java代理机制 的基础知识&#xff1b; 【1】代理相关 1.1&#xff09;利用代理可以在运行时创建一个实现了一组给定接口的新类&#xff0c; 这种功能只有在 编译时无法确定需要实…

织梦mysql安装教程视频教程_织梦DedeCMSV6系统安装步骤教程

DedeCMSV6系统基于PHP7.*MySQL开发&#xff0c;本篇文档将介绍如何下载DedeCMSV6系统&#xff0c;并且通过之前已经部署好的系统环境来安装配置一个安全的站点。准备工作&#xff1a;主机一台(PHP7.0以上MYSQL)域名(做好解析绑定工作)源码下载通过DedeCMSV6系统下载页面可以获取…

无法创建t的通用数组_创建通用数组的问题

无法创建t的通用数组在这篇文章中&#xff0c;我们将介绍一篇全面的文章&#xff0c;其中介绍了创建通用数组的问题。 Java编程语言于2004年9月在Java 5.0“ Tiger”发行版中添加了泛型。 泛型或类型参数化系统在提供类型安全性的同时扩展了Java现有的类型系统。 1.简介 Java具…

贪婪算法+小应用(调度问题)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 旨在 理解 “DFS应用——贪婪算法” 的idea&#xff1b; 【1】贪婪算法 1.1&#xff09;已经看到的三个贪婪算法&#xff1a; Dijkstra算、Prim算法 和 Kruskal 算法&#xff1b;&#xff08;Dijkstr…

http 安全性和幂等性_HTTP方法:幂等性和安全性

http 安全性和幂等性幂等性和安全性是HTTP方法的属性。 HTTP RFC定义了这些属性&#xff0c;并告诉我们哪些HTTP方法是安全且幂等的。 服务器应用程序应确保正确执行安全和幂等的语义&#xff0c;如客户端期望的那样。 安全的HTTP方法 如果HTTP方法不更改服务器状态&#xff0…

Huffman编码(Huffman树)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “Huffman编码&#xff08;Huffman树&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; Huffman树的构建算法属于 贪婪算法&#xff0c;…

java获取文件列表_java获取指定目录中的文件列表

最近项目中会动态生成文件html及相关资源文件(css,js,png,mp3)&#xff0c;为了防止文件名重复&#xff0c;需要获取目录中相同类型文件的最大编号&#xff0c;下面我用代码来实现获得文件列表。public static void getFiles(String path) {File file new File(path);// 如果这…

jep290涉及jdk版本_针对JDK 14提议的另外六个JEP

jep290涉及jdk版本Mark Reinhold最近的消息宣布了六个新的“建议针对JDK 14的JEP ”&#xff1a; JEP 345 &#xff0c; JEP 361 &#xff0c; JEP 363 &#xff0c; JEP 364 &#xff0c; JEP 365和JEP 367 。 假设没有异议由11月7日提出&#xff0c;这些JEPs将有针对性地JDK …

近似装箱问题(三种联机算法实现)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “近似装箱问题&#xff08;三种联机算法实现&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 近似装箱问题的三种联机算法 分别是&am…

java 随机数种子_Java--随机数和随机数种子(转)

在计算机中并没有一个真正的随机数发生器&#xff0c;但是可以做到使产生的数字重复率很低&#xff0c;这样看起来好象是真正的随机数&#xff0c;实现这一功能的程序叫伪随机数发生器。有关如何产生随机数的理论有许多&#xff0c;如果要详细地讨论&#xff0c;需要厚厚的一本…

java 堆转储快照_捕获Java堆转储的7个选项

java 堆转储快照堆转储是诊断与内存相关的问题的重要工件&#xff0c;例如内存泄漏缓慢&#xff0c;垃圾回收问题和java.lang.OutOfMemoryError。它们也是优化内存消耗的重要工件。 有很棒的工具&#xff0c;例如Eclipse MAT和Heap Hero&#xff0c;可以分析堆转储。 但是&…

java 提取url参数_Java提取URL某个参数的值

ASP&period;NET Core 中文文档 第四章 MVC(4&period;3)过滤器原文:Filters 作者:Steve Smith 翻译:刘怡(AlexLEWIS) 校对:何镇汐 ASP.NET MVC 过滤器 可在执行管道的前后特定阶段执行代码.过滤器可以配置为全局有效.仅对控 ...jquery插件-表单提交插件-jQuery&peri…

近似装箱问题(两种脱机算法实现)

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “近似装箱问题&#xff08;两种脱机算法实现&#xff09;” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 近似装箱问题的两种联机算法 分别是&am…

vaadin 10+_Vaadin 10+作为CUBA UI的未来

vaadin 10从一开始&#xff0c;Vaadin就成为CUBA平台用户界面的基石和重要组成部分。 凭借其创新的方法&#xff0c;它帮助CUBA将企业用户界面开发带到了一个非常有希望&#xff08;当今是默认&#xff09;的WEB领域。 Vaadin最令人兴奋的部分之一是整个开发都是同构的&#xf…

java 信息增益_对信息增益(IG,Information Gain)的理解和计算

可能理解的不对。决策树构建中节点的选择靠的就是信息增益了。信息增益是一种有效的特征选择方法&#xff0c;理解起来很简单&#xff1a;增益嘛&#xff0c;肯定是有无这个特征对分类问题的影响的大小&#xff0c;这个特征存在的话&#xff0c;会对分类系统带来多少信息量&…

使用文本编辑器和jdk_JDK 14:记录,文本块等

使用文本编辑器和jdk今天的Mark Reinhold帖子“ 建议JEP针对JDK 14&#xff1a;305、343、359、366和368 ”建议将另外五个JEP针对JDK 14 。 该组中有一些备受期待的功能&#xff0c;但建议将所有功能都“预览”或“孵化”&#xff1a; JEP 305 &#xff1a;instanceof的模式匹…