__getattribute__拦截所有属性访问,__getattr__仅在属性未找到且__getattribute__抛出AttributeError时触发;前者需用super()避免递归,后者更安全常用。

__getattribute__ 会拦截所有属性访问,__getattr__ 只在属性找不到时触发
这是最根本的差异。只要写 obj.attr 或调用 getattr(obj, 'attr'),__getattribute__ 就一定被调用;而 __getattr__ 只有在 Python 按照「实例 __dict__ → 类 __dict__ → 父类链」都查不到该属性、且 __getattribute__ 抛出 AttributeError 时,才会执行。
__getattribute__ 容易引发无限递归,必须用 super() 调用父类逻辑
如果你在 __getattribute__ 里写 self.logger 或 self.__dict__,就会再次触发 __getattribute__,死循环。常见避坑方式:
- 对内部依赖属性(如
logger、__dict__、_cache)做白名单判断,直接super().__getattribute__(name) - 永远不要在
__getattribute__中使用点号访问任何属性,除非你明确知道它不会再次触发自己 -
super().__getattribute__(name)等价于object.__getattribute__(self, name),这是唯一安全的原始访问方式
__getattr__ 更安全、更常用,适合动态属性和兜底逻辑
因为不参与常规查找流程,__getattr__ 不会干扰已有属性,也不用担心递归。典型用途包括:
- 实现类似
obj.column_name映射数据库字段的 ORM 风格访问 - 为缺失属性返回默认值或占位对象,避免到处写
hasattr()或getattr(obj, 'x', default) - 懒加载计算属性:
if name == 'expensive': self._expensive = compute(); return self._expensive
两者共存时,__getattribute__ 的异常会“降级”到 __getattr__
如果类同时定义了两个方法,__getattribute__ 先执行;它若主动抛 AttributeError(比如拒绝访问以 cur 开头的属性),解释器不会让程序崩溃,而是继续调用 __getattr__ —— 这是唯一能让 __getattr__ 被触发的合法路径。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
注意:这个“降级”只对 AttributeError 有效,其他异常(如 TypeError、ValueError)会直接冒泡出去。
真正容易被忽略的是:__getattribute__ 的开销是全局性的,每次点号访问都进一次,哪怕只是读 obj.__class__;而 __getattr__ 是惰性触发,对性能无额外负担。选哪个,本质是在“全面控制”和“按需兜底”之间做权衡。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










