python属性访问优先调用__getattribute__(每次访问都触发,负责完整查找流程),仅当其抛出attributeerror时才调用__getattr__(仅兜底处理不存在的属性)。

Python中属性访问不是简单查字典,而是一套有严格优先级的机制。理解__getattribute__和__getattr__的分工与触发时机,是写出可预测、可调试的对象行为的关键。
__getattribute__:每次属性访问都经过它
__getattribute__是属性访问的“守门人”,只要对象支持该方法(所有新式类默认继承自object,都具备),**每次**通过点号(obj.attr)或getattr()访问任意属性时,都会先调用它。它负责整个查找流程的调度——包括实例字典、类字典、父类MRO链、描述符协议等。
⚠️ 注意:在__getattribute__内部访问自身属性(如self.__dict__)必须用super().__getattribute__,否则会无限递归。
- 它比
__getattr__更底层、更早执行 - 即使属性存在,也会被拦截;若抛出
AttributeError,才可能继续走__getattr__ - 重写时务必小心,避免意外阻断正常访问(比如忘记处理
__dict__、__class__等特殊属性)
__getattr__:仅当常规查找失败后才调用
__getattr__是“兜底函数”——只有当Python按标准顺序(实例__dict__ → 类及MRO中数据描述符 → 类及MRO中非数据描述符/普通属性)都找不到目标属性时,才会调用它。它不参与常规属性命中流程。
立即学习“Python免费学习笔记(深入)”;
- 适用于实现动态属性、代理模式、日志记录或提供默认值
- 不会影响已存在的属性访问,安全性更高
- 例如:
obj.missing_attr触发__getattr__,但obj.existing_attr完全绕过它
两者典型协作场景
常见做法是用__getattribute__做统一拦截(如审计、权限检查),再把“查不到”的情况交给__getattr__处理;或者只用__getattr__实现轻量级动态行为,避开__getattribute__的复杂性。
- 想记录所有属性读取?重写
__getattribute__,并在最后调用super()委托 - 只想给不存在的属性返回默认值(如
None或计算结果)?直接定义__getattr__即可 - 同时定义两者时,确保
__getattribute__在抛出AttributeError前已穷尽所有查找路径
一个简明对比示例
假设类A中定义了__getattribute__和__getattr__:
→ 访问a.x(x存在):只进__getattribute__,不进__getattr__
→ 访问a.y(y不存在):先进__getattribute__,查无结果并抛AttributeError,再进__getattr__
这种分层设计让Python既保持灵活性,又不牺牲性能和可预测性。










