Python属性查找顺序为:先实例字典→再按MRO遍历类字典→描述符协议介入→特殊方法绕过常规流程。实例属性遮蔽类属性;MRO决定多重继承中同名属性优先级;描述符(如@property)可定制访问逻辑;特殊方法需在类中定义。
Python中对象属性查找遵循明确的顺序规则,核心是MRO(Method Resolution Order)和描述符协议共同作用的结果。理解这个顺序,能避免属性访问异常、正确覆盖父类行为,并写出更可靠的面向对象代码。
访问对象属性时,Python首先在实例的__dict__中查找。如果找到,直接返回值,不再继续搜索。这解释了为什么给实例动态赋值同名属性会“遮蔽”类属性或父类方法。
obj.x = 10后,obj.x始终返回10,即使类中定义了x = 20或父类有x方法del obj.x后,再次访问obj.x将按后续规则继续查找实例字典未命中时,Python按该对象所属类的MRO序列(从左到右、深度优先但C3线性化)依次在每个类的__dict__中查找。MRO可通过ClassName.__mro__或ClassName.mro()查看。
当在类字典中查到一个对象,且该对象实现了__get__(以及可选__set__/__delete__),它就是一个描述符。此时Python不直接返回该对象,而是调用其__get__(instance, owner)方法——这意味着属性行为可被完全定制。
@property修饰的方法本质是data descriptor(有__set__),优先级高于实例字典中的同名属性__get__)优先级低于实例字典,但高于普通类属性以双下划线开头和结尾的特殊方法(如__len__、__add__)不完全遵循上述顺序。Python在特定
操作(如len(obj))中,会直接在对象的类(而非实例)中查找,且不触发描述符协议(即不会调用__get__)。
obj.__len__ = lambda: 42对len(obj)无效__getattr__仅在常规查找全部失败后才被调用,用于兜底处理;而__getattribute__则拦截所有属性访问(慎用)