`getattr`如何与`object .__ getattribute__`和`object .__ getattr__`相关?

时间:2017-07-08 23:21:01

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

来自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__的关系如何?

getattrobject.__getattribute__还是object.__getattr__?我猜这个前者?

2 个答案:

答案 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__(如果存在):

  1. AttributeError__getattribute__
  2. 引发
  3. __getattribute__明确地称之为
  4. 来自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方法。