python中super的理解(转)
原文地址:https://www.zhihu.com/question/20040039
针对你的问题,答案是可以,并没有区别。但是这题下的回答我感觉都不够好。
要谈论 super,首先我们应该无视 "super" 这个名字带给我们的干扰。
不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!
不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!
不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!
一说到 super 就想到父类这是初学者很容易犯的一个错误,也是我当年犯的错误。
忘记了这件事之后,再去看这篇文章:Python’s super() considered super!
这是 Raymond Hettinger 写的一篇文章,也是全世界公认的对 super 讲解最透彻的一篇文章,凡是讨论 super 都一定会提到它(当然还有一篇 Python's Super Considered Harmful)。
如果不想看长篇大论就去看这个答案,super 其实干的是这件事:
def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
两个参数 cls 和 inst 分别做了两件事:
1. inst 负责生成 MRO 的 list
2. 通过 cls 定位当前 MRO 中的 index, 并返回 mro[index + 1]
这两件事才是 super 的实质,一定要记住!
MRO 全称 Method Resolution Order,它代表了类继承的顺序。后面详细说。
举个例子
class Root(object):
def __init__(self):
print("this is Root")
class B(Root):
def __init__(self):
print("enter B")
# print(self) # this will print <__main__.D object at 0x...>
super(B, self).__init__()
print("leave B")
class C(Root):
def __init__(self):
print("enter C")
super(C, self).__init__()
print("leave C")
class D(B, C):
pass
d = D()
print(d.__class__.__mro__)
输出
enter B
enter C
this is Root
leave C
leave B
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)
知道了 super 和父类其实没有实质关联之后,我们就不难理解为什么 enter B 下一句是 enter C 而不是 this is Root(如果认为 super 代表“调用父类的方法”,会想当然的认为下一句应该是this is Root)。流程如下,在 B 的 __init__ 函数中:
super(B, self).__init__()
首先,我们获取 self.__class__.__mro__,注意这里的 self 是 D 的 instance 而不是 B 的
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)
然后,通过 B 来定位 MRO 中的 index,并找到下一个。显然 B 的下一个是 C。于是,我们调用 C 的 __init__,打出 enter C。
顺便说一句为什么 B 的 __init__ 会被调用:因为 D 没有定义 __init__,所以会在 MRO 中找下一个类,去查看它有没有定义 __init__,也就是去调用 B 的 __init__。
其实这一切逻辑还是很清晰的,关键是理解 super 到底做了什么。
于是,MRO 中类的顺序到底是怎么排的呢?Python’s super() considered super!中已经有很好的解释,我翻译一下:
在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。
最后的最后,提醒大家.
什么 super 啊,MRO 啊,都是针对 new-style class。如果不是 new-style class,就老老实实用父类的类名去调用函数吧。
--
更新,回答
的问题。
class A(object) :
def __init__(self, strName, *args) :
self.name = strName
super(A, self).__init__(*args)
class B(object) :
def __init__(self, iID) :
self.ID= iID
class C(A, B):
def __init__(self, *args)
super(C, self).__init__(*args)
没有考虑 keyword 参数,如果要要考虑,也是类似的,加后面就行了
python中super的理解(转)的更多相关文章
- Java 泛型 <? super T> 中 super 怎么 理解?与 < ? extends T>有何不同?
Java 泛型 <? super T> 中 super 怎么 理解?与 extends 有何不同? 简介 前两篇文章介绍了泛型的基本用法.类型擦除以及泛型数组.在泛型的使用中,还有个重要的 ...
- 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的时候,产生了一些疑惑,super在python中的用法跟其他的语言有一些不一样的地方,在网上找了一些资料,发现基本上很少有文章能把我的疑惑讲明白 ...
- Python中super函数的用法
之前看python文档的时候发现许多单继承类也用了super()来申明父类,那么这样做有何意义? 从python官网文档对于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中使用@的理解
Python函数中使用@ 稍提一下的基础 fun 和fun()的区别 以一段代码为例: def fun(): print('fun') return None a = fun() #fun函数并将返回 ...
随机推荐
- 初探Linux内核中的内存管理
Linux内核设计与实现之内存管理的读书笔记 初探Linux内核管理 内核本身不像用户空间那样奢侈的使用内存; 内核不支持简单快捷的内存分配机制, 用户空间支持? 这种简单快捷的内存分配机制是什么呢? ...
- oracle 12514文件解决
listener.ora的SID_LIST_LISTENER添加一下内容 (SID_DESC = (GLOBAL_DBNAME = ORCL) (ORACLE_HOME = f:\app\Admini ...
- zabbix添加对haproxy的监控
zabbix添加对haproxy的监控 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.HAProxy本身提供一个web页面 ...
- centos如何安装Python3
Linux下默认系统自带python2.6的版本,这个版本被系统很多程序所依赖,所以不建议删除,如果使用最新的Python3那么我们知道编译安装源码包和系统默认包之间是没有任何影响的,所以可以安装py ...
- python字符串,列表常用操作
24天养成一个好习惯,第五天! 一.字符串需要掌握的操作 1.取值(索引取值)需要注意的是只能取,不能改 msg = 'hello world' print(msg[4]) 2.切片(顾头不顾尾) m ...
- Oracle Package的全局变量与Session
Oracle Package的全局变量与Session2012-07-26 aaie_ 阅 3595 转 10简单讲,同一个session下pageckage中的全局变量时公共的,会导致冲突.以下是一 ...
- nodejs和ionic小助手
nodejs已经安装完成的情况下,安装ionic小助手 win+r打开cmd. 命令: 1.node -v(查看版本信息) 2.npm -v(查看版本信息) 3.npm install -g cnpm ...
- textarea中的回车识别问题
<textarea name="" id="aa" cols="30" rows="10" wrap=" ...
- -Dmaven.multiModuleProjectDirectory system property is not set.
1.配置 maven 环境变量 新建系统变量 -> 变量名(N): M2_HOME 变量值(V): D:\apache-maven-3.5.4(改为自己的maven目录) -> 添加 pa ...
- UEFI rootkit 工具LoJax可以感染电脑主板(mainboard)
1.UEFI(Unified Extensible Firmware Interface)统一扩展接口,UEFI rootkit是以在UEFI中植入rootkit ,18年9月份ESET首次公开了境外 ...