`__getattribute__` 和 `__getattr__` 中的错误处理

Posted

技术标签:

【中文标题】`__getattribute__` 和 `__getattr__` 中的错误处理【英文标题】:Error handling in `__getattribute__` and `__getattr__` 【发布时间】:2020-01-04 19:59:58 【问题描述】:

注意此问题已在 cmets 中得到解答

我注意到__getattribute____getattr__ 中的一些异常处理行为,我在文档或此处的其他帖子中找不到。

考虑这个类A。如果A 的实例具有None 属性,则访问该属性会引发AttributeError

class A:
    def __getattribute__(self, item):
        value = object.__getattribute__(self, item)
        if value is None:
            raise AttributeError('in __getattribute__')

        return value

    def __init__(self, a=None):
        self.a = a

A(1).a  # 1
A().a  # raises AttributeError('in __getattribute__')

现在,__getattribute__ 上的 docs 说

无条件调用以实现类实例的属性访问。如果该类还定义了__getattr__(),则不会调用后者,除非__getattribute__() 明确调用它或引发AttributeError

由此,我猜想__getattribute__ 中引发的任何AttributeError 总是会被捕获,并且该过程会延迟到__getattr__,这样调用者就永远不会看到AttributeError('in __getattribute__')

令我惊讶的是,不仅看到了错误,而且在A().a 上引发的AttributeError__getattribute__ 中的错误,好像从未调用过__getattr__。那是 除非 __getattr__ 提出自己的

def __getattr__(self, item):
    raise AttributeError('in __getattr__')

在这种情况下,我们会看到 AttributeError('in __getattr__') 被提升。

这里有什么规则?如果我在__getattribute__ 中提出AttributeError 的一些子类Oops 而不是AttributeError('in __getattribute__'),它们是否适用?

【问题讨论】:

If the class also defines __getattr__() - 你的班级没有定义__getattr__ @snakecharmerb 很好奇,继承自 object__getattr__ 会发生什么? 奇怪 - object 上没有 __getattr__(试试 object.__getattr__)。那么object.__getattr__ 的文档是什么意思? ah, "可以定义以下方法来自定义类实例的属性访问(使用、分配或删除 x.name)的含义。" 那么这里有什么问题呢?我没有看到。 【参考方案1】:

总结 cmets。

[Python 3.Docs]: Data model - object.__getattribute__(self, name)(强调是我的)声明:

无条件调用以实现类实例的属性访问。 如果该类还定义了__getattr__(),则不会调用后者,除非__getattribute__() 明确调用它或引发AttributeError。此方法应返回(计算的)属性值或引发AttributeError 异常。为了避免这个方法无限递归,它的实现应该总是调用同名的基类方法来访问它需要的任何属性,例如,object.__getattribute__(self, name)

混淆是因为假设 __getattr__ 是从 object 继承的(这是错误的):

>>> dir(object)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>>
>>> object.__getattribute__
<slot wrapper '__getattribute__' of 'object' objects>
>>> object.__getattr__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__getattr__'

虽然我可以理解为什么它可能会让某些人感到困惑,但从我所关心的(在多次阅读 doc 之后)来看,这很清楚:如果 __getattr__ 是从 object 继承的,那么(引用的)文本“If the class also defined __getattr__()”将没有意义 .

【讨论】:

以上是关于`__getattribute__` 和 `__getattr__` 中的错误处理的主要内容,如果未能解决你的问题,请参考以下文章

Python——管理属性

python中__getattr__和__getattribute__区别

关于__getattr__和__getattribute__的一些问题?

python中__get__,__getattr__,__getattribute__的区别

python中__get__,__getattr__,__getattribute__的区别

python3中__get__,__getattr__,__getattribute__的区别