我试图理解什么时候定义__getattr__或__getattribute__。python文档提到__getattribute__适用于新样式的类。什么是新型类?


当前回答

__getattr__和__getattribute__之间的一个关键区别是,__getattr__只在没有以通常的方式找到属性时才会被调用。它很适合为缺失的属性实现回退,并且可能是您想要的两种方法之一。

__getattribute__是在查看对象上的实际属性之前调用的,因此正确实现可能很棘手。你可以很容易地得到无限递归。

新类型的类派生于object,旧类型的类是Python 2中的类。没有显式基类的X。但是在__getattr__和__getattribute__之间进行选择时,旧风格和新风格类之间的区别并不是重要的一个。

你几乎肯定想要__getattr__。

其他回答

在阅读Beazley & Jones PCB时,我偶然发现了__getattr__的一个明确而实际的用例,它有助于回答OP问题的“何时”部分。摘自书中:

"The __getattr__() method is kind of like a catch-all for attribute lookup. It's a method that gets called if code tries to access an attribute that doesn't exist." We know this from the above answers, but in PCB recipe 8.15, this functionality is used to implement the delegation design pattern. If Object A has an attribute Object B that implements many methods that Object A wants to delegate to, rather than redefining all of Object B's methods in Object A just to call Object B's methods, define a __getattr__() method as follows:

def __getattr__(self, name):
    return getattr(self._b, name)

其中_b是Object A的属性(Object B)的名称。当Object B上定义的方法在Object A上被调用时,__getattr__方法将在查找链的末尾被调用。这也会使代码更干净,因为您不需要为委托给另一个对象而定义一个方法列表。

我发现没有人提到这个区别:

__getattribute__有默认实现,但__getattr__没有。

class A:
    pass
a = A()
a.__getattr__ # error
a.__getattribute__ # return a method-wrapper

这有一个明确的含义:因为__getattribute__有默认实现,而__getattr__没有,显然python鼓励用户实现__getattr__。

getattribute:用于从实例中检索属性。它通过使用点表示法或getattr()内置函数捕获访问实例属性的每次尝试。 getattr:当在对象中找不到属性时,作为最后一个资源执行。您可以选择返回一个默认值或引发AttributeError。

返回__getattribute__函数;如果没有覆盖默认实现;执行该方法时执行以下检查:

检查MRO链中的任何类中是否定义了同名(属性名)的描述符(方法对象解析) 然后查看实例的名称空间 然后查看类名称空间 然后进入每个基的名称空间,等等。 最后,如果未找到,默认实现将调用实例的回退getattr()方法,并作为默认实现引发AttributeError异常。

这是对象的实际实现。__getattribute__方法:

.. c:function:: PyObject* PyObject_GenericGetAttr(PyObject *o, PyObject *name) Generic attribute getter function that is meant to be put into a type object's tp_getattro slot. It looks for a descriptor in the dictionary of classes in the object's MRO as well as an attribute in the object's :attr:~object.dict (if present). As outlined in :ref:descriptors, data descriptors take preference over instance attributes, while non-data descriptors don't. Otherwise, an :exc:AttributeError is raised.

新型类是直接或间接继承“object”的类。除了__init__之外,它们还有一个__new__类方法,并且有一些更合理的低级行为。

通常,你会想要重写__getattr__(如果你重写了其中任何一个),否则你将很难支持“self”。方法中的Foo语法。

额外信息:http://www.devx.com/opensource/Article/31482/0/page/4

__getattr__和__getattribute__之间的一个关键区别是,__getattr__只在没有以通常的方式找到属性时才会被调用。它很适合为缺失的属性实现回退,并且可能是您想要的两种方法之一。

__getattribute__是在查看对象上的实际属性之前调用的,因此正确实现可能很棘手。你可以很容易地得到无限递归。

新类型的类派生于object,旧类型的类是Python 2中的类。没有显式基类的X。但是在__getattr__和__getattribute__之间进行选择时,旧风格和新风格类之间的区别并不是重要的一个。

你几乎肯定想要__getattr__。