Python:为什么 __getattr__ 会捕获 AttributeErrors?

新手上路,请多包涵

我正在为 __getattr__ 苦苦挣扎。我有一个复杂的递归代码库,让异常传播很重要。

 class A(object):
    @property
    def a(self):
        raise AttributeError('lala')

    def __getattr__(self, name):
        print('attr: ', name)
        return 1

print(A().a)

结果是:

 ('attr: ', 'a')
1

为什么会有这种行为?为什么不抛出异常?此行为未记录( __getattr__ 文档)。 getattr() 可以只使用 A.__dict__ 。有什么想法吗?

原文由 Dave Halter 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 525
1 个回答

在同一个类中使用 __getattr__ 和属性是危险的,因为它会导致很难调试的错误。

如果属性的 getter 抛出 AttributeError ,则 AttributeError 被静默捕获,并调用 __getattr__ 通常,这会导致 __getattr__ 以异常失败,但如果你非常不幸,它不会,你甚至无法轻松地将问题追溯到 __getattr__

编辑:这个问题的示例代码可以在 这个答案 中找到。

除非你的财产吸气剂是微不足道的,否则你永远不能 100% 确定它不会抛出 AttributeError 。异常可能会被抛出几个层次。

这是您可以执行的操作:

  1. 避免在同一类中使用属性和 __getattr__
  2. 添加一个 try ... except 块到所有不平凡的属性获取器
  3. 保持属性获取器简单,这样你就知道它们不会抛出 AttributeError
  4. 编写您自己版本的 @property 装饰器,它捕获 AttributeError 并将其重新抛出为 RuntimeError

另见 http://blog.devork.be/2011/06/using-getattr-and-property_17.html

编辑:如果有人正在考虑解决方案 4(我不推荐),可以这样做:

 def property_(f):
    def getter(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except AttributeError as e:
            raise RuntimeError, "Wrapped AttributeError: " + str(e), sys.exc_info()[2]

    return property(getter)

然后在覆盖 @property 的类中使用 @property_ 而不是 __getattr__

原文由 Florian Winter 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题