python super

调用父类方法

为了调用父类(超类)的一个方法,可以使用 super() 函数,比如:

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

class A(object):
    def spam(self):
        print('A.spam')

class B(A):
    def spam(self):
        print('B.spam')
        #A.spam(self)       #直接调用父类方法
        super(B,self).spam()

b = B()
b.spam()

super() 函数的一个常见用法是在 __init__() 方法中确保父类被正确的初始化了:

class A(object):
    def __init__(self):
        self.x = 0

class B(A):
    def __init__(self):
        super(B,self).__init__()
        self.y = 1

b = B()
print(b.x)
print(b.y)

不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!
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 A(Root):
    def __init__(self):
        print("enter A")
        super(A, self).__init__()
        print("leave A")

class B(Root):
    def __init__(self):
        print("enter B")
        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(A, B, C):
    def __init__(self):
        print("enter D")
        super(D, self).__init__()
        print("leave D")

d = D()
print(d.__class__.__mro__)

#输出结果:
#enter D
#enter A
#enter B
#enter C
#this is Root
#leave C
#leave B
#leave A
#leave D
#(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

原理: 对于你定义的每一个类而言,Python会计算出一个所谓的方法解析顺序(MRO)列表。 这个MRO列表就是一个简单的所有基类的线性顺序表。如:

(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

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

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

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

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

当你使用 super() 函数时,Python会在MRO列表上继续搜索下一个类。 只要每个重定义的方法统一使用 super() 并只调用它一次, 那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次

note

super ,MRO ,都是针对 new-style class。如果不是 new-style class,就只能用父类的类名去调用函数啦。

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值