Python对象属性查找顺序_访问规则说明【指导】

12次阅读

python属性查找顺序为:先实例字典→再按MRO遍历类字典→描述符协议介入→特殊方法绕过常规流程。实例属性遮蔽类属性;MRO决定多重继承中同名属性优先级;描述符(如@Property)可定制访问逻辑;特殊方法需在类中定义。

Python对象属性查找顺序_访问规则说明【指导】

Python中对象属性查找遵循明确的顺序规则,核心是MRO(Method Resolution Order)和描述符协议共同作用的结果。理解这个顺序,能避免属性访问异常、正确覆盖父类行为,并写出更可靠的面向对象代码。

实例字典优先于类字典

访问对象属性时,Python首先在实例的__dict__中查找。如果找到,直接返回值,不再继续搜索。这解释了为什么给实例动态赋值同名属性会“遮蔽”类属性或父类方法。

  • 例如:obj.x = 10后,obj.x始终返回10,即使类中定义了x = 20或父类有x方法
  • 删除实例属性:del obj.x后,再次访问obj.x将按后续规则继续查找

按MRO顺序遍历类及其父类

实例字典未命中时,Python按该对象所属类的MRO序列(从左到右、深度优先但C3线性化)依次在每个类的__dict__中查找。MRO可通过ClassName.__mro__ClassName.mro()查看。

  • 多重继承下,MRO确保每个父类只被搜索一次,且子类总在父类之前
  • 若多个父类定义同名属性,靠前的类中定义的版本生效(非“最近父类”,而是MRO中位置最前)
  • 注意:类变量和实例方法都走此路径;但方法调用会额外触发绑定(bound method)机制

描述符协议介入属性访问

当在类字典中查到一个对象,且该对象实现了__get__(以及可选__set__/__delete__),它就是一个描述符。此时Python不直接返回该对象,而是调用其__get__(instance, owner)方法——这意味着属性行为可被完全定制。

立即学习Python免费学习笔记(深入)”;

  • 函数、property、classmethod、staticmethod 都是内置描述符
  • @property修饰的方法本质是data descriptor(有__set__),优先级高于实例字典中的同名属性
  • 非数据描述符(只定义__get__)优先级低于实例字典,但高于普通类属性

特殊方法名绕过常规查找

以双下划线开头和结尾的特殊方法(如__len____add__)不完全遵循上述顺序。Python在特定操作(如len(obj))中,会直接在对象的类(而非实例)中查找,且不触发描述符协议(即不会调用__get__)。

  • 因此,在实例上设置obj.__len__ = Lambda: 42len(obj)无效
  • 重载运算符必须在类定义中实现,不能靠实例赋值覆盖
  • 例外:__getattr__仅在常规查找全部失败后才被调用,用于兜底处理;而__getattribute__则拦截所有属性访问(慎用)
text=ZqhQzanResources