Python MRO

文中代码基于Python3.7

对于Python中的多继承情况,运行时在搜索对象的属性或方法时,需要遵循一定的顺序规则,这个规则称为:Method Resolution Order (MRO).

MRO规则可以总结为以下三句话:

  • In the multiple inheritance scenario, any specified attribute is searched first in the current class. If not found, the search continues into parent classes in depth-first, left-right fashion without searching the same class twice.
  • So, first it goes to super class (and its super classes) given first in the list then second super class (and its super classes) , from left to right order. Then finally Object class, which is a super class for all classes. 这里的list指的是多个父类组成的list,如: class M(X,Y,Z): pass list就是(X,Y,Z)
  • When in MRO we have a super class before subclass then it must be removed from that position in MRO. 这一句和第一句对应起来看,一个类只被检索一次,所以基类要往后移

可以调用类型对象的mro方法或者__mro__属性来获取类型的MRO信息。

class X:
    def hello(self):
        print('x')
​
​
class Y:
    def hello(self):
        print('y')
    
    def world(self):
        print('y_world')
​
​
class Z:
    def hello(self):
        print('z')
​
​
class A(X):
    def hello(self):
        print('a')
​
​
class B(Y,Z):
    def hello(self):
        print('b')
​
​
class M(B, A): 
    pass
​
print(M.mro())
print(M.__mro__)
​
# 输出:
# list类型
[<class '__main__.M'>, <class '__main__.B'>, <class '__main__.Y'>, <class '__main__.Z'>, <class '__main__.A'>, <class '__main__.X'>, <class 'object'>]
# tuple类型
(<class '__main__.M'>, <class '__main__.B'>, <class '__main__.Y'>, <class '__main__.Z'>, <class '__main__.A'>, <class '__main__.X'>, <class 'object'>)

MRO图示如下:

goes to super class (and its super classes) given first in the list then second super class (and its super classes) , from left to right order. Then finally Object class

depth-first, left-right fashion without searching the same class twice ,得到MRO列表:[<class '__main__.M'>, <class '__main__.B'>, <class '__main__.Y'>, <class '__main__.Z'>, <class '__main__.A'>, <class '__main__.X'>, <class 'object'>]


B和A均继承自Z,M继承自B和A:

class X:
    def hello(self):
        print('x')
​
​
class Y:
    def hello(self):
        print('y')
    
    def world(self):
        print('y_world')
​
​
class Z:
    def hello(self):
        print('z')
​
​
class A(X,Z):
    def hello(self):
        print('a')
​
​
class B(Y,Z):
    def hello(self):
        print('b')
​
​
class M(B, A): 
    pass
​
print(M.mro())
​
# 输出:
# [<class '__main__.M'>, <class '__main__.B'>, <class '__main__.Y'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.Z'>, <class 'object'>]

MRO图示如下:

goes to super class (and its super classes) given first in the list then second super class (and its super classes) , from left to right order. Then finally Object class

depth-first, left-right fashion without searching the same class twice ,得到MRO列表:[<class '__main__.M'>, <class '__main__.B'>, <class '__main__.Y'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.Z'>, <class 'object'>]


class X:
    def hello(self):
        print('x')
​
​
class Y:
    def hello(self):
        print('y')
    
    def world(self):
        print('y_world')
​
​
class Z:
    def hello(self):
        print('z')
​
​
class A(X,Z):
    def hello(self):
        print('a')
​
​
class B(Y,Z):
    def hello(self):
        print('b')
​
​
class M(B, A, Y): 
    pass
​
print(M.mro())
​
# 输出
# [<class '__main__.M'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.Y'>, <class '__main__.X'>, <class '__main__.Z'>, <class 'object'>]

MRO图示如下:

goes to super class (and its super classes) given first in the list then second super class (and its super classes) , from left to right order. Then finally Object class

这个MRO图可以继续简化:

depth-first, left-right fashion without searching the same class twice

得到MRO列表为[<class '__main__.M'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.Y'>, <class '__main__.X'>, <class '__main__.Z'>, <class 'object'>]


When in MRO we have a super class before subclass then it must be removed from that position in MRO

下面是一个会报错的示例:

class A:
    def process(self):
        print('A process()')
​
​
class B(A):
    def process(self):
        print('B process()')
​
​
class M(A, B):
    pass
​
print(M.mro())
​
# 输出:
# TypeError: Cannot create a consistent method resolution
# order (MRO) for bases A, B

MRO图示:

如果一个方法或属性同时存在与B和A,应为M直接继承B又直接继承A,那么通过M来调用时就不知道是该从B中还是A中获取这个方法或属性了,干脆就报错吧。我觉得MRO顺序应该为:M->B->A->object。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • T-SQL基础(五)之增删改

    在前面的文章中对T-SQL的查询做了基本总结,接下来我们看下SQL中的另外一个常用操作——数据的修改。

    雪飞鸿
  • T-SQL基础(五)之增删改

    在前面的文章中对T-SQL的查询做了基本总结,接下来我们看下SQL中的另外一个常用操作——数据的修改。

    雪飞鸿
  • Python实现单链表和字典

    雪飞鸿
  • SpringMVC类图关系

    package org.springframework.web.servlet {

    zhangheng
  • 菱形继承问题

    在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

    py3study
  • 深入浅出 Runtime(六):相关面试题

    目的是将实例和类的相关方法列表以及构建信息区分开来,方便各司其职,符合单一职责设计原则。

    师大小海腾
  • [第22期] React Conf 2019 样式新方案

    会上讲了很多激动人心的技术点,这里先介绍一些我比较感兴趣的点, 希望对大家有所启发。

    用户6900878
  • 「基础编程学习」 「PHP7数组详解」:第1章 (8)数组和对象

    举一个例子,比如说一个班级,有一个班级号,班级名,描述,房间号,教导员,班级人数。可以存到一个数组内,这样写:

    程序员小助手
  • 34.python issubclass函数

    返回值 — 如果child_class  是 father_class  的子类,返回True,否则返回 False;

    猿说编程[Python和C]
  • 使用Nginx代理restful实现SSL链路加密

    1 目标说明 1.1 调研目的 本次调研主要为了解决两个问题: 不需要对restful的web容器做任何配置,实现对restful链路进行加密; 方便restf...

    囚兔

扫码关注云+社区

领取腾讯云代金券