【Python基础】方法解析顺序MRO及Super的用法

本文详细解释了Python中多继承时的MethodResolutionOrder(MRO)特别是C3算法的三个特性:局部优先顺序、单调性和扩展优先顺序图。同时介绍了Super类的用法及其在MRO中的作用。
摘要由CSDN通过智能技术生成

方法解析顺序MRO

        在Python的多继承里面,不熟悉MRO可能会在逐级继承时调用哪一个父类的方法产生困惑,本篇文章就针对python多继承时的MRO展开解析。Python的多继承使用的是C3算法来计算MRO,

具体的C3算法可搜索其他文章,本文章就针对C3算法的三个性质展开说明。

        C3算法性质一:local precedence order,局部优先顺序。假设A,B类如下:

class A:
    def say(self):
        print("say A")


class B:
    def say(self):
        print("say B")

 当进行多继承的时候,M就会优先使用写在前面的class的方法,实例如下:

class M(B, A):
    pass


m = M()
print(M.mro())
m.say()         # Say B
class M(A, B):
    pass


m = M()
print(M.mro())
m.say()         # Say A

这就是局部优先顺序的性质,当创建出新的子类并且继承自M时,那么M的所有子类也要遵循局部优先顺序的特性

        C3算法性质二:monotonicity, 单调性。简述其意思:任何一个class所使用的方法必须来自于自直接父类的方法,不能调过父类继续向上找。举例说明:A,B类还是如上图,

class C(A):
    pass


class D(C, B):
    pass


class M(D):
    pass


m = M()
print(M.mro())
m.say()     # say A

print的结果还是A,M只继承D,按照单调性,M的直接方法只能来自于父类iD,D的方法只能来自于父类C,B,按照局部优先顺序,D会先搜索父类C的say方法,最后发现父类C的say方法是Say A,所以M的say方法就是say A。

        C3算法性质三:extended precedence graph。拿下图举例,该性质研究的是scrolling-mixin和editing-mixin对于他们子类的继承优先顺序。首先需要找到scrolling-mixin和editing-mixin的最小公共子类,很明显edtitable-scrollable-pane就是他们的最小公共子类。

        对于最小公共子类来说,只要scrolling-mixin或者scrolling-mixin的子类排在editing-mixin或者editing-mixin子类之前,那么scrolling-mixin的mro位置就要比editing-mixin靠前,对于editing-mixin同理。

         所以在python多继承时就要MRO就要满足上述性质,不满足则会抛出异常。如下:A,B还是一样,M同时继承C,D,根据局部优先顺序,C要求其子类先A后B,D要求其子类先B后A,M同时继承C,D,但C,D的局部优先顺序不一致,导致M无法计算出线性的MRO抛出异常。

class C(A, B):
    pass


class D(B, A):
    pass


class M(C, D):
    pass


m = M()
print(M.mro())
m.say()

TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, B

Super的用法

        其实Super是一个类,日常见到比较多的情况下如下:super()的形式,括号里的参数缺省。其实缺省的两个参数分别是:Person, self。

class Animal:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age


class Person(Animal):
    def __init__(self, name: str, age: int, gender: str):
        self.gender = gender
        super().__init__(name, age)

        super(param1, param2)中的param1参数类型必须是类,param2的参数类型可以是一个类或者一个对象。param2决定了使用怎样的 mro。param1决定了从 mro 哪个 class 后面的 class 开始寻找,并将函数绑定到第二个参数上。

        以下图为例,Man类初始化函数下的super(Person, self),self指的就是Man类对象,计算其MRO为[Man, Person, Animal, Object],Person后的第一个类为Animal,所以super构造的是Animal类的对象,并将其绑定到了man类对象下。

class Animal:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age


class Person(Animal):
    def __init__(self, name: str, age: int, gender: str):
        self.gender = gender
        super(Person, self).__init__(name, age)


class Man(Person):
    def __init__(self, name: str, age: int, phone: str):
        self.phone = phone
        super(Person, self).__init__(name, age)

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值