__getattr__仅在属性查找失败时调用,__setattr__需用object.__setattr__()避免递归;二者适用于动态属性场景如配置封装、API代理,但要注意性能、继承及权限控制。

__getattr__ 什么时候才被调用?
它只在属性查找失败时触发,不是每次访问都走这里。比如 obj.x 找不到 x,才会进 __getattr__;如果 x 已经存在(哪怕值是 None),就不会调用它。
常见错误是误以为它能拦截所有属性访问,结果发现赋值后读取没进方法——因为属性已经存在了。
- 仅对未定义的属性生效,不覆盖已存在的实例属性或类属性
- 如果想统一拦截所有读取(包括存在的),得用
__getattribute__,但它更重、容易递归崩溃,一般不推荐 - 返回值会被当作属性值直接使用,所以别忘了 return,否则默认返回
None
__setattr__ 怎么避免无限递归?
在 __setattr__ 里给实例设属性时,如果直接写 self.name = value,会再次触发 __setattr__,导致 RecursionError。
正确做法是绕过自定义逻辑,直接操作底层字典:object.__setattr__(self, name, value) 或 self.__dict__[name] = value。
立即学习“Python免费学习笔记(深入)”;
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
- 优先用
object.__setattr__(self, name, value),它更安全,能兼容父类有自定义__setattr__的情况 -
self.__dict__[name] = value在有__slots__时会报错,不能用 - 如果要过滤某些属性名(比如禁止设置
_internal),在这里加判断最自然
动态属性常用于哪些真实场景?
不是为了炫技,而是解决具体问题:比如封装配置字典、代理远程 API 字段、懒加载计算属性。
典型例子是把 JSON 响应转成对象,字段名不确定,又不想提前声明:
class DynamicConfig:
def __init__(self, data):
self._data = data
<pre class='brush:python;toolbar:false;'>def __getattr__(self, name):
if name in self._data:
return self._data[name]
raise AttributeError(f"'{type(self).__name__}' has no attribute '{name}'")
def __setattr__(self, name, value):
if name == '_data':
object.__setattr__(self, name, value)
else:
# 允许写入 _data 中已有的 key,其他拒绝
if hasattr(self, '_data') and name in self._data:
self._data[name] = value
else:
raise AttributeError(f"Cannot set unknown config key: {name}")</pre>- 注意区分读写权限:
__getattr__可以返回任意计算值,__setattr__要明确控制是否允许写 - 如果数据源是只读的(如 API 返回),
__setattr__直接 raise 更清晰 - 调试时打印
name和value是最快定位问题的方式
性能和继承要注意什么?
这两个方法是 Python 属性访问链的最后环节,开销比普通属性高不少。高频访问的字段不该靠它们动态生成。
另外,子类继承时,如果父类已定义 __getattr__,子类没重写,那父类逻辑依然生效;但 __setattr__ 不会自动委托给父类,必须显式调用 super().__setattr__(...) 或 object.__setattr__(...)。
- 不要在
__getattr__里做耗时操作(比如网络请求),除非你清楚这是懒加载且调用频次低 - 子类若需扩展
__setattr__,记得先处理自己的逻辑,再调用父类或object.__setattr__ - 用
hasattr(obj, 'x')检查属性时,也会触发__getattr__,这点容易被忽略
真正难的不是写对这两个方法,而是判断某个需求到底该用它们,还是该用 @property、__getattribute__ 或者干脆重构数据结构。

















