AttributeError的属性和__getattr__兼容性问题

时间:2014-08-04 09:19:48

标签: python properties

我刚遇到一个意想不到的行为。这是一个简单的类,其中包含__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有关但是这个问题有一个很好的干净的解决方法吗?因为我可以向你保证,这是一个调试噩梦......

2 个答案:

答案 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的子类objectsuper().__getattribute__(attr)等效于object.__getattribute__(self, attr)。读取a的基础object属性,避免了如果我们改为使用self.__getattribute__(attr)的无限递归。

AttributeError的情况下,我们可以完全控制失败或重新筹集资金,并且重新筹集会给出明智的错误消息。