我刚遇到一个意想不到的行为。这是一个简单的类,其中包含__getattr__
方法和属性属性,其中包含拼写错误:
class A(object):
def __getattr__(self, attr):
if not attr.startswith("ignore_"):
raise AttributeError(attr)
@property
def prop(self):
return self.some_typo
a = A() # Instantiating
a.ignore_this # This is ignored
a.prop # This raises an Attribute Error
这是预期的结果(如果__getattr__
被评论,我得到的结果):
AttributeError: 'A' object has no attribute 'some_typo'
这就是我得到的:
AttributeError: prop
我知道这与__getattr__
捕获AttributeError
有关但是这个问题有一个很好的干净的解决方法吗?因为我可以向你保证,这是一个调试噩梦......
答案 0 :(得分:4)
您可以提出更好的异常消息:
class A(object):
def __getattr__(self, attr):
if not attr.startswith("ignore_"):
raise AttributeError("%r object has not attribute %r" % (self.__class__.__name__, attr))
@property
def prop(self):
return self.some_typo
a=A()
a.ignore_this
a.prop
编辑:从对象基类调用__getattribute__
解决了问题
class A(object):
def __getattr__(self, attr):
if not attr.startswith("ignore_"):
return self.__getattribute__(attr)
@property
def prop(self):
return self.some_typo
答案 1 :(得分:0)
如@asmeurer所述,@ mguijarr的解决方案两次调用prop
。当prop
第一次运行时,它会引发AttributeError并触发__getattr__
。然后self.__getattribute__(attr)
再次触发prop
,最终导致所需的异常。
更好的答案:
在这里,我们最好替换__getattribute__
而不是__getattr__
。由于__getattribute__
在所有属性访问上都被调用,因此它可以提供更多控制权。相比之下,__getattr__
仅在已经存在AttributeError
时调用,并且它不能使我们访问该原始错误。
class A(object):
def __getattribute__(self, attr):
try:
return super().__getattribute__(attr)
except AttributeError as e:
if not attr.startswith("ignore_"):
raise e
@property
def prop(self):
print("hi")
return self.some_typo
为了说明,由于在这种情况下A
的子类object
,super().__getattribute__(attr)
等效于object.__getattribute__(self, attr)
。读取a
的基础object
属性,避免了如果我们改为使用self.__getattribute__(attr)
的无限递归。
在AttributeError
的情况下,我们可以完全控制失败或重新筹集资金,并且重新筹集会给出明智的错误消息。