为何__getattr__被调用而非捕获AttributeError?Python2.7方案咨询
这个问题其实是Python 2.7中属性查找机制的典型表现——当父类定义了__getattr__时,访问不存在的属性会优先调用这个方法,而不是抛出AttributeError,所以你的try-except块才没触发。下面有两种既保留Base的__getattr__又能维持try-except逻辑的解决方案:
方案1:在Derived类中重写__getattr__,针对特定属性抛出异常
这种方法能精确控制哪些属性需要触发AttributeError,其他属性仍然沿用父类的__getattr__行为:
class Base: def __init__(self): pass def __getattr__(self, item): print('__getattr__ was called!') class Derived(Base): def __getattr__(self, item): # 当访问'val'且属性不存在时,直接抛出AttributeError if item == 'val': raise AttributeError("'Derived' object has no attribute '%s'" % item) # 其他属性交给父类的__getattr__处理 return super(Derived, self).__getattr__(item) def GetValue(self): try: return self.val except AttributeError: self.val = 1 return self.val obj = Derived() print(obj.GetValue()) # 输出1,不会触发Base的__getattr__ print(obj.non_existent) # 触发Base的__getattr__,打印'__getattr__ was called!'
方案2:直接检查实例的__dict__
Python实例的属性会存储在__dict__字典中,我们可以通过检查这个字典来判断val是否已初始化,同时保留try-except块:
class Base: def __init__(self): pass def __getattr__(self, item): print('__getattr__ was called!') class Derived(Base): def GetValue(self): try: # 先检查val是否在实例的属性字典中,不在则主动抛出异常 if 'val' not in self.__dict__: raise AttributeError('val') return self.val except AttributeError: self.val = 1 return self.val obj = Derived() print(obj.GetValue()) # 输出1
原理说明
- 方案1通过重写
__getattr__,对目标属性val直接抛出AttributeError,让try-except块能够捕获到,而其他属性仍正常触发父类的__getattr__。 - 方案2利用了Python实例属性的存储机制:未初始化的
val不会出现在self.__dict__中,此时主动抛出异常,确保except块执行初始化逻辑,同时不会触发父类的__getattr__。
内容的提问来源于stack exchange,提问作者Michal
相关产品推荐
相关产品推荐

