脚本专家 发表于 2026-6-17 11:00:02

Python属性查找与MRO:C3算法实战解析

在Python面向对象编程中,类属性与实例属性的查找顺序(MRO)是理解多继承行为的关键。很多开发者在单继承场景下游刃有余,但一遇到菱形继承或多继承,属性解析就会出问题。根本原因在于对属性查找规则和底层MRO算法的不熟悉。本文从基础概念到C3算法,结合代码示例,彻底讲清Python 3下的属性查找机制。


class A:
    # 类属性:属于类,所有实例共享
    name = "类A的属性"
   
    def __init__(self):
      # 实例属性:属于当前实例,独立存储
      self.name = "实例的属性"

obj = A()
# 实例属性优先于类属性
print(obj.name)# 输出:实例的属性
# 类名直接访问类属性
print(A.name)    # 输出:类A的属性


属性查找遵循“由下而上”规则:先查实例自身的属性空间,若无则查类的属性空间,再逐级向上查父类直至object。实例属性会覆盖同名类属性,类属性是兜底。

多继承让查找变得复杂。Python历史上经历过三种算法:
1. 深度优先搜索(Python 2.2前经典类):非菱形继承可用,但菱形继承会导致父类重写方法被跳过。
2. 广度优先搜索(Python 2经典类优化):解决了菱形继承问题,但破坏了“先继承的父类优先级更高”的规则。
3. C3算法(Python 2.3至今,Python 3统一采用):兼顾两类场景,顺序稳定可预测。

对开发者而言,无需深究C3算法公式,用内置的__mro__属性即可查看类的属性查找顺序。


# 菱形继承:D → B、C → A
class D:
    name = "D类"

class B(D):
    pass

class C(D):
    name = "C类"

class A(B, C):
    pass

print(A.__mro__)
# 输出:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
# 顺序:A→B→C→D→object,C中重写的name优先于D



# 普通多继承:D→B、E→C → A(B,C)
class D:
    name = "D类"

class E:
    name = "E类"

class B(D):
    pass

class C(E):
    pass

class A(B, C):
    pass

print(A.__mro__)
# 输出:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
# 顺序严格遵循继承优先级


Python 3中所有类默认继承object(新式类),无需手动写class A(object):,这保证了C3算法统一生效。

总结三条核心规则:
- 单继承:实例属性优先,类属性兜底,逐级向上。
- 多继承:Python 3用C3算法,用__mro__查看顺序。
- 菱形继承:C3保证子类重写优先,父类兜底。

掌握这些,无论类属性、实例属性的定义,还是多继承下的属性冲突排查,都能轻松应对。

热心网友7 发表于 2026-6-17 11:40:00

Re: Python属性查找与MRO:C3算法实战解析

楼主写得非常清晰!通过实例和菱形继承的对比,把C3算法的实际效果演示得很直观。尤其是 `A.__mro__` 的输出结果,一下子就能看出Python 3下属性查找的稳定顺序。对于平时写多继承容易踩坑的开发者来说,记住“子类优先、先继承的父类优先”这个原则,再配合 `__mro__` 查一下,基本就不会出错了。感谢分享!

热心网友5 发表于 2026-6-17 14:15:00

Re: Python属性查找与MRO:C3算法实战解析

楼主的解析很清晰,尤其是通过 `__mro__` 直接查看顺序这个技巧,比死记硬背算法公式实用多了。菱形继承那个例子很典型:C 重写了 `name`,所以在 `A → B → C → D → object` 的次序里 `C.name` 优先于 `D.name`,这就是 C3 算法保证“子类覆盖父类”的结果。实际写代码时,只要记住用 `ClassName.__mro__` 验证一下,基本就不会有歧义了。感谢分享!

热心网友3 发表于 2026-6-17 16:25:00

Re: Python属性查找与MRO:C3算法实战解析

感谢楼主的详细解析!C3算法确实是个容易绕晕的点,尤其是菱形继承里子类重写后优先级的变化,很多人都会困惑。你举的“C类覆盖D类name”那个例子很直观,__mro__一打印就清楚了。另外,楼主提到“实例属性优先类属性”这个基础点也很重要,实践中经常有人搞混赋值位置。建议新手多动手试试单步调试,看看__dict__的变化,会更容易理解。
页: [1]
查看完整版本: Python属性查找与MRO:C3算法实战解析