Python中如何避免__getattr__方法陷入死循环的问题
class Proxy:
def init(self, obj):
# self._obj = obj,则调用__getattr__就会死循环,而改成 self._obj = obj,则不会;
self.obj = obj
def getattr(self, item):
return getattr(self.obj, item)
class Spam:
def init(self, x):
self.x = x
def bar(self, y):
print(‘Spam.bar:’, self.x, y)
if name == “main”:
spam = Spam(10.05)
proxy = Proxy(spam)
print(proxy.x)
仅仅是将 Proxy 实例属性由_obj 的成 obj,就会造成__getattr__无限循环,这个怎么理解?谢谢。
Python中如何避免__getattr__方法陷入死循环的问题
在Python里,__getattr__方法只在属性查找失败时被调用。但如果在这个方法内部又去访问一个不存在的属性,就会再次触发__getattr__,导致无限递归。要解决这个问题,核心是确保在__getattr__内部进行属性访问时,能明确地“绕开”它自身的触发机制。
最直接有效的方法是利用object.__getattribute__或者super().__getattribute__。这两个方法会直接调用默认的属性查找逻辑,而不会再次进入你自定义的__getattr__。
下面是一个典型的错误示例和修正后的代码:
错误示例(会导致死循环):
class BadExample:
def __getattr__(self, name):
# 错误:这里尝试访问 self.data,但data属性不存在。
# 这会导致再次调用 __getattr__('data'),陷入死循环。
return self.data.get(name)
正确做法:
class SafeExample:
def __init__(self):
# 使用 object.__setattr__ 来绕过可能的 __setattr__ 重写
object.__setattr__(self, '_data', {'foo': 'bar'})
def __getattr__(self, name):
# 关键:使用 object.__getattribute__ 来安全地访问内部属性 _data
# 这不会再次触发 __getattr__
internal_data = object.__getattribute__(self, '_data')
if name in internal_data:
return internal_data[name]
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
# 测试
obj = SafeExample()
print(obj.foo) # 输出: bar
print(obj.baz) # 触发 AttributeError
代码解释:
- 在
__init__中,我们使用object.__setattr__来设置一个内部字典_data。这是为了避免如果类中还重写了__setattr__可能带来的副作用。 - 在
__getattr__内部,我们使用object.__getattribute__(self, '_data')来获取这个内部字典。这个调用直接使用了对象最基础的属性获取机制,确保了它不会回头来调用我们正在写的这个__getattr__方法。 - 然后我们检查请求的
name是否在字典中,如果在就返回,否则抛出标准的AttributeError。
总结一下: 在__getattr__里访问其他属性时,用object.__getattribute__()或super().__getattribute__()来安全地获取。
哈哈,楼主肯定是在__init__初始化函数改了,忘记在 getattr 里面修改了,导致在获取的时候无线循环一直到报 error
<script src=“https://gist.github.com/zhusimaji/df879dd537a6729b6201f456e2c08b71.js”></script>
谢谢二位,原因找到了!有一段__setattr__的代码没贴出来,在__setattr__中调用了__getattr__,没做一些拦截处理,造成重复调用__getattr__,话说,这几个魔术方法真是死循环的高危险操作呢


