查看: 125|回复: 3

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

[复制链接]
发表于 6 小时前 | 显示全部楼层 |阅读模式
在Python面向对象编程中,类属性与实例属性的查找顺序(MRO)是理解多继承行为的关键。很多开发者在单继承场景下游刃有余,但一遇到菱形继承或多继承,属性解析就会出问题。根本原因在于对属性查找规则和底层MRO算法的不熟悉。本文从基础概念到C3算法,结合代码示例,彻底讲清Python 3下的属性查找机制。
  1. class A:
  2.     # 类属性:属于类,所有实例共享
  3.     name = "类A的属性"
  4.    
  5.     def __init__(self):
  6.         # 实例属性:属于当前实例,独立存储
  7.         self.name = "实例的属性"
  8. obj = A()
  9. # 实例属性优先于类属性
  10. print(obj.name)  # 输出:实例的属性
  11. # 类名直接访问类属性
  12. print(A.name)    # 输出:类A的属性
复制代码

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

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

对开发者而言,无需深究C3算法公式,用内置的__mro__属性即可查看类的属性查找顺序。
  1. # 菱形继承:D → B、C → A
  2. class D:
  3.     name = "D类"
  4. class B(D):
  5.     pass
  6. class C(D):
  7.     name = "C类"
  8. class A(B, C):
  9.     pass
  10. print(A.__mro__)
  11. # 输出:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
  12. # 顺序:A→B→C→D→object,C中重写的name优先于D
复制代码
  1. # 普通多继承:D→B、E→C → A(B,C)
  2. class D:
  3.     name = "D类"
  4. class E:
  5.     name = "E类"
  6. class B(D):
  7.     pass
  8. class C(E):
  9.     pass
  10. class A(B, C):
  11.     pass
  12. print(A.__mro__)
  13. # 输出:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
  14. # 顺序严格遵循继承优先级
复制代码

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

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

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

使用道具 举报

发表于 5 小时前 | 显示全部楼层

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

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

使用道具 举报

发表于 2 小时前 | 显示全部楼层

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

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

使用道具 举报

发表于 半小时前 | 显示全部楼层

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

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

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-17 17:00 , Processed in 0.039837 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部