【问题标题】:How is `getattr` related to `object.__getattribute__` and to `object.__getattr__`?`getattr` 与 `object.__getattribute__` 和 `object.__getattr__` 有什么关系?
【发布时间】:2017-12-12 23:33:34
【问题描述】:

来自https://docs.python.org/3.6/library/functions.html#getattr

getattr(object, name[, default])

返回object 的命名属性的值。名称必须是 细绳。如果字符串是对象属性之一的名称, 结果是该属性的值。例如,getattr(x, 'foobar') 等价于 x.foobar。如果命名属性确实 不存在,default 如果提供则返回,否则返回 AttributeError 被提出。

getattrobject.__getattribute__object.__getattr__ 有什么关系?

getattr 是否调用 object.__getattribute__object.__getattr__?我猜是前者?

【问题讨论】:

  • 所有这些__getattr__ 问题都令人麻木......

标签: python python-3.x operators built-in magic-methods


【解决方案1】:

getattr(foo, 'bar')(基本上是foo.bar)调用__getattribute__,然后可以在以下情况下调用__getattr__(如果存在):

  1. AttributeError__getattribute__ 提出
  2. __getattribute__ 明确调用它

来自docs

如果该类还定义了__getattr__(),则不会调用后者 除非__getattribute__() 明确调用它或引发 AttributeError.

如果您不想在随机属性访问中引发属性错误,定义__getattr__ 会很有用。 Mock library 就是一个很好的例子。

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.foo.bar.spam
<Mock name='mock.foo.bar.spam' id='4367274280'>

如果您不想一直定义__getattr__,也不想一直处理AttributeError,那么您可以使用getattr() 的3 参数形式在未找到属性时返回默认值或使用hasattr 来检查它是否存在。

>> getattr([], 'foo')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-60-f1834c32d3ce> in <module>()
----> 1 getattr([], 'foo')

AttributeError: 'list' object has no attribute 'foo'
>>> getattr([], 'foo', 'default')
'default'

演示:

class A:
    def __getattr__(self, attr):
        print('Inside A.__getattr__')
        return 'eggs'

print(A().foo)

输出:

Inside A.__getattr__
eggs

请注意,数据模型文档指出它为object.__getattr__,但这并不意味着它们存在于内置object 类型中。相反,它们通常可以存在于任何对象上。在这种情况下,对象是一种类型,因为 dunder 方法是在对象的类型上查找的。​​p>

【讨论】:

  • 谢谢。 __getattr__object 的方法吗?所以默认情况下所有东西都有__getattr__,因为所有东西都继承object
  • @Tim object.__getattr__ 不存在(可能是因为在那里没有__geattr__AttributeError 就是我们所需要的),但是用户定义的类可以有一个自定义的@ 987654352@ 处理属性错误。 __getattr__ 存在于 Python 2 的旧式类中。
  • @Tim 可以存在于对象上,不代表内置的object类型。
  • @Tim 您可以自己查看:hasattr(object, '__getattr__')
【解决方案2】:

总结答案

一般来说,虚线查找调用 __getattribute__。

如果__getattribute__ 中的代码没有找到该属性,它会查看是否定义了__getattr__。如果是,则调用它。否则,会引发 AttributeError

getattr() 函数只是调用上述方法的另一种方式。例如getattr(a, 'x') 等价于a.x

getattr() 函数主要在您事先不知道属性名称时(即当它存储在变量中时)有用。例如,k = 'x'; getattr(a, k) 等价于 a.x

类比和高级观点

最好的理解方式是 __getattribute__ 是第一个调用的主要方法,而 __getattr__ 是在缺少属性时调用的后备方法。这样一来,就很像__getitem____missing__在字典中查找方括号的关系了。

演示代码

这是一个经过验证的示例:

>>> class A(object):
    x = 10
    def __getattribute__(self, attr):
        print(f'Looking up {attr!r}')
        return object.__getattribute__(self, attr)
    def __getattr__(self, attr):
        print(f'Invoked the fallback method for missing {attr!r}')
        return 42

>>> a = A()
>>> a.x
Looking up 'x'
10
>>> a.y
Looking up 'y'
Invoked the fallback method for missing 'y'
42

>>> # Equivalent calls with getattr()
>>> getattr(a, 'x')
Looking up 'x'
10
>>> getattr(a, 'y')
Looking up 'y'
Invoked the fallback method for missing 'y'
42

官方文档

以下是文档的相关部分:

object.__getattr__(self, name) 属性查找时调用 在通常的地方找不到该属性(即它不是 instance 属性也没有在 self 的类树中找到)。姓名 是属性名称。此方法应返回(计算) 属性值或引发 AttributeError 异常。

注意如果属性是通过正常机制找到的, __getattr__() 未被调用。 (这是 __getattr__() 和 __setattr__() 之间的故意不对称。)这样做既是出于效率原因,也是因为否则 __getattr__() 将无法 访问实例的其他属性。请注意,至少对于 实例变量,您可以通过不插入任何 实例属性字典中的值(而是插入 它们在另一个对象中)。请参阅下面的 __getattribute__() 方法 真正获得对属性访问的完全控制的方法。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 2015-09-30
    • 2019-12-06
    相关资源
    最近更新 更多