Python 属性访问的 MRO 规则

MRO(Method Resolution Order,方法解析顺序)是 Python 中多继承环境下 查找属性和方法的确定性顺序 。Python 使用 C3 线性化算法来计算 MRO。

一、MRO 的规则

1. 查找顺序

复制代码
class A:
    value = "A"

class B(A):
    value = "B"

class C(B):
    pass

c = C()
print(c.value)  # 输出: B

查找路径:

复制代码
C → B → A → object

2. 查找规则

规则 说明
从左到右 多继承时,先查第一个父类,再查第二个
从下到上 先查子类,再查父类
子类优先 子类会覆盖父类的同名属性
C3 线性化 保证单调性(不会出现不一致的顺序)

二、MRO 的确定方法

1. 使用 __mro__ 查看

复制代码
class GrandParent:
    pass

class Parent1(GrandParent):
    pass

class Parent2(GrandParent):
    pass

class Child(Parent1, Parent2):
    pass

print(Child.__mro__)

输出:

复制代码
(<class '__main__.Child'>, 
 <class '__main__.Parent1'>, 
 <class '__main__.Parent2'>, 
 <class '__main__.GrandParent'>, 
 <class 'object'>)

2. 使用 mro() 方法

复制代码
print(Child.mro())  # 与 __mro__ 相同,但返回列表

3. 使用 help(ClassName) 查看

复制代码
help(Child)
# 会显示 Method resolution order 部分

三、C3 线性化算法原理

1. 算法核心公式

复制代码
L[C(B1...BN)] = C + merge(L[B1], L[B2], ..., L[BN], B1...BN)

其中:

  • L[C] 表示类 C 的线性化结果

  • merge 是合并操作,保证顺序

2. 手动计算示例

复制代码
class O: pass
class A(O): pass
class B(O): pass
class C(A, B): pass

计算过程:

复制代码
L[O] = O
L[A] = A + merge(L[O], O) = A + merge(O, O) = A, O
L[B] = B, O
L[C] = C + merge(L[A], L[B], A, B)
     = C + merge([A,O], [B,O], [A,B])
     = C + [A] + merge([O], [B,O], [B])
     = C + [A,B] + merge([O], [O])
     = C + [A,B,O]

结果 :C → A → B → O

四、多继承的 MRO 示例

菱形继承

复制代码
class A:
    value = "A"

class B(A):
    value = "B"

class C(A):
    value = "C"

class D(B, C):
    pass

print(D.__mro__)
print(D.value)  # 输出: B

MRO:

复制代码
D → B → C → A → object

查找 value:

  1. D:没有 → 2. B:有 "B" → 停止

五、属性访问的查找流程

代码验证

复制代码
class Descriptor:
    def __get__(self, instance, owner):
        return "描述符的值"

class Parent:
    class_attr = "父类的类属性"
    desc = Descriptor()

class Child(Parent):
    pass

c = Child()

# 1. 实例属性
c.instance_attr = "实例属性"
print(c.instance_attr)  # 实例属性

# 2. 类属性(按 MRO)
print(c.class_attr)     # 父类的类属性

# 3. 描述符(特殊处理)
print(c.desc)           # 描述符的值

方法的查找和属性的查找在 Python 中遵循完全相同的规则 。因为方法本质上就是绑定在类上的属性 ,只不过这个属性是可调用的函数。

相关推荐
武天旭3 小时前
AI安全--AI大模型的毒性偏见与安全对齐实践
人工智能·python·深度学习
视觉小萌新4 小时前
AI Class 3 · Chapter 2-3:函数、异常、文件读写+JSON / JSONL 读写(小白版)
人工智能·python·json
小小张说故事5 小时前
Python 的 obj.x 到底按什么顺序找?拆开数据描述符、实例字典和 __getattr__ 那条优先级链
python
用户11481867894846 小时前
水印的实现方式逻辑
前端·python
贾公子6 小时前
从单条内容到账号维度——AIGC 风险评分的工程实现
后端·python
木头左7 小时前
【Python】不点浏览器发博客:逆向 CSDN 创作中心接口做 md-publish 技能
python·自动化·api
Tt有了t8 小时前
设计模式速查
java·python·设计模式
deepseek238 小时前
Python日志拖慢请求?QueueHandler排队、丢失与退出实测
python·性能优化·logging·后端开发·queuehandler
用户91294046848428 小时前
Codex 从零到能交付(05):第一次改代码:生成一个文件清单脚本
python
Dmz丶8 小时前
前端转 AI 100 天 Day 38:Token 管理与成本优化——别让 API 账单爆炸
python