来自https://docs.python.org/3.6/library/functions.html#getattr
getattr(object, name[, default])
返回
object
的命名属性的值。名字必须是 串。如果字符串是对象属性之一的名称, 结果是该属性的值。例如,getattr(x, 'foobar')
相当于x.foobar
。如果命名属性 如果不存在,则返回default
,否则返回AttributeError
被提出。
getattr
与object.__getattribute__
和object.__getattr__
的关系如何?
getattr
是object.__getattribute__
还是object.__getattr__
?我猜这个前者?
答案 0 :(得分:4)
通常,虚线查找会调用__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)在属性查找时调用 没有在通常的地方找到属性(即它不是 实例属性也不是在类树中找到的自我)。名称 是属性名称。这个方法应该返回(计算) 属性值或引发AttributeError异常。
请注意,如果通过正常机制找到属性, 不调用__getattr __()。 (这是__getattr __()和__setattr __()之间的故意不对称。)这是出于效率原因而做的,因为否则__getattr __()将无法 访问实例的其他属性。请注意,至少为 实例变量,你可以通过不插入任何来伪造总控制 实例属性字典中的值(而是插入 他们在另一个对象)。请参阅下面的__getattribute __()方法 实际上可以完全控制属性访问的方法。
object .__ getattribute __(self,name)无条件调用 实现类的实例的属性访问。如果上课 还定义了__getattr __(),后者不会被调用,除非 __getattribute __()要么显式调用它,要么引发 AttributeError 。此方法应返回(计算)属性 值或引发 AttributeError 异常。为了避免无限 在这个方法中递归,它的实现应该总是调用 具有相同名称的基类方法可以访问它的任何属性 需要,例如,object .__ getattribute __(self,name)。
答案 1 :(得分:3)
getattr(foo, 'bar')
(基本上是foo.bar
)调用__getattribute__
并且可以在以下情况下调用__getattr__
(如果存在):
AttributeError
由__getattribute__
__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方法。