理解 Python super

本文深入探讨Python中super()函数的使用与原理,解释其在类继承中的作用并非仅限于调用父类方法,而是指向MRO中的下一个类。通过实例说明super()如何正确地在多重继承中调用初始化方法。

原文地址:https://laike9m.com/blog/li-jie-python-super,70/

 

理解 Python super

今天在知乎回答了一个问题,居然一个赞都没有,也是神奇,毕竟这算是我非常认真答的题之一。既然如此就贴过来好了,有些内容之后再补充。

原问题

Python中既然可以直接通过父类名调用父类方法为什么还会存在super函数?
比如
class Child(Parent):
    def __init(self):
    Parent.__init
(self)
这种方式与super(Child, self).init()有区别么?

回答
针对你的问题,答案是可以,并没有区别。但是这题下的回答我感觉都不够好。

要谈论 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 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。
关于 MRO 的官方文档参见:The Python 2.3 Method Resolution Order,有一些关于 MRO 顺序的理论上的解释。

最后的最后,提醒大家. 什么 super 啊,MRO 啊,都是针对 new-style class。如果不是 new-style class,就老老实实用父类的类名去调用函数吧。

基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样与统计,通过模拟系统元件的故障与修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构与设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码与案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行与可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理与实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估与优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值