Python属性查找顺序为:__getattribute__ → 实例__dict__ → 类及MRO中各父类__dict__(含描述符优先触发__get__)→ __getattr__(仅全程AttributeError时调用);__getattribute__每次访问必触发,需委托object.__getattribute__避免递归,而__getattr__仅为兜底钩子。

Python类属性查找顺序:从实例到基类的完整链路
Python查找一个属性时,不是简单地“先找实例再找类”,而是有一条严格定义的路径。这条路径决定了你看到的是哪个值,也解释了为什么有时修改类属性会意外影响所有实例。
查找顺序是:__getattribute__ → 实例字典 __dict__ → 类及MRO中各父类的__dict__ → 触发__getattr__(仅当前面全失败)。
-
__getattribute__是入口闸门,**每次**访问属性(包括__dict__本身)都会调用它;绕过它唯一安全的方式是用object.__getattribute__(self, name) - 如果
__getattribute__抛出AttributeError,且你没捕获,Python才会继续走后续路径,最后尝试__getattr__ - MRO顺序很重要:多继承下,Python按
C.__mro__从左到右搜索类字典,不是“就近原则” - 描述符(如
@property、classmethod)在类字典中被识别并优先触发其__get__,这发生在查完实例字典之后、但早于普通类属性返回
__getattribute__ 为什么不能直接 return self.__dict__[name]?
这么写会导致无限递归——因为访问self.__dict__本身就会再次触发__getattribute__。
正确做法是委托给父类实现:
立即学习“Python免费学习笔记(深入)”;
librosa 是一个用于音频和音乐分析的 Python 库。它提供了特征提取、频谱分析、节拍跟踪、起始检测和音频可视化的工具,基于 NumPy 和 SciPy 构建,用于科学音频计算。
def __getattribute__(self, name):
if name == "special":
return "hardcoded"
# ✅ 安全:跳过自定义逻辑,交给object处理
return object.__getattribute__(self, name)
- 永远不要在
__getattribute__里用self.xxx或getattr(self, xxx)访问任何属性,包括__dict__、__class__ - 如果真要读实例字典,用
object.__getattribute__(self, "__dict__").get(name),但通常没必要 - 重写
__getattribute__是高危操作,99%的场景用__getattr__或描述符更安全
__getattr__ 只在属性完全找不到时才调用
__getattr__不是“备用查找函数”,而是“兜底钩子”。它不会干扰正常属性访问流程,只在整条链路都失败后启动。
常见误用是以为它能拦截所有访问,结果发现@property、类变量、甚至拼错的实例属性都没进这个方法——因为它们在前面环节已被命中或抛出了其他异常(比如KeyError)。
- 只有
AttributeError会被捕获并导向__getattr__;TypeError、KeyError等会直接冒泡 -
__getattr__适合做动态属性代理、日志记录、API兼容层,例如:if name.startswith("data_"): return self._load_data(name[5:]) - 它不能用于覆盖已有属性行为(比如让
obj.x返回不同值),那得用__getattribute__或描述符
描述符和@property如何插入查找链条?
描述符对象(实现了__get__/__set__)一旦出现在类字典中,就会在“查完实例字典、准备返回类属性前”被拦截执行。这就是@property能工作的原因。
关键点在于:描述符协议优先级高于普通类属性,但低于实例属性。也就是说:
- 实例字典中有
x→ 直接返回,不碰描述符 - 实例字典无
x,类字典中有描述符x→ 调用其__get__ - 类字典中只有普通值
x = 42→ 直接返回42,不经过任何协议 -
__getattribute__可以阻止描述符触发(比如它提前返回了值),但__getattr__完全插不上手
最容易忽略的是:描述符必须定义在**类上**,放在实例上无效;而且它的__get__接收instance参数,为None时表示被类访问(如C.x)。

















