__getattr__只在属性查找失败时触发,__getattribute__拦截所有访问但易因self.xxx引发无限递归,须用object.__getattribute__(self, name)安全委托。

别用 __getattr__ 去拦截所有属性访问——它只在属性不存在时才触发;真要全程拦截,必须用 __getattribute__,但一不小心就会递归崩溃。
为什么 __getattr__ 总是不生效?
这是最常见的误用点:__getattr__ 不是“每次取属性都调用”,而是“仅当属性查找不到时才 fallback”。比如你给实例设置了 self.name = "alice",再访问 obj.name 就根本不会进 __getattr__。
- 适用场景:实现默认值、动态代理缺失属性(如字典式访问)、日志记录未定义字段
- 错误写法:
return self.__dict__.get(name)—— 这会绕过 Python 的正常查找逻辑,且无法处理 property、描述符等 - 正确姿势:只做兜底,比如
if name.startswith("fallback_"): return getattr(self._backend, name[9:]) - 注意:
__getattr__不能抛出AttributeError,否则会无限递归(因为异常触发再次查找__getattr__)
__getattribute__ 怎么写才不崩溃?
它在每次属性访问时都无条件触发,包括访问 self.__dict__、self.__class__ 甚至你自己写的其他方法——所以直接在里面读属性,大概率触发递归调用自己。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 必须用
object.__getattribute__(self, name)调用父类实现来安全获取属性,而不是self.xxx或self.__dict__[name] - 常见坑:
if name == "x": return self._x→ 这里self._x又触发__getattribute__,死循环 - 性能敏感:它比
__getattr__重得多,频繁调用会明显拖慢对象访问速度 - 示例安全写法:
def __getattribute__(self, name): if name == "special": return "intercepted" return object.__getattribute__(self, name)
两者能一起用吗?怎么分工?
可以,而且推荐:用 __getattribute__ 处理“所有访问”的通用逻辑(比如审计、权限检查),再让 __getattr__ 处理“确实找不到”的情况(比如动态生成、fallback 到其他对象)。
- 顺序固定:
__getattribute__先执行;如果它没抛异常也没返回,Python 才继续找属性;找不到才调__getattr__ - 典型组合:
__getattribute__拦截敏感字段(如_secret)并抛PermissionError;__getattr__把未知字段转给内部_data字典处理 - 注意:
__getattribute__里若手动抛AttributeError,会直接跳到__getattr__,不是跳过它
真正难的不是语法,是判断哪个钩子该承担哪部分责任——尤其当对象有继承、有描述符、有 @property 时,__getattribute__ 的行为会和直觉偏差很大。动手前先用 dir(obj) 和 hasattr 确认目标属性是否真的“不存在”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










