了解__getattr__和__getattribute__之间的区别

我想了解__getattr____getattribute__之间的区别,但是,我失败了。

堆栈溢出问题getattrgetattribute之间的区别说,

在查看对象上的实际属性之前调用__getattribute__ ,因此可能会很难正确实现。 你可以很容易地在无限的recursion结束。

我完全不知道这意味着什么。

然后它继续说:

你几乎肯定希望__getattr__

为什么?

我读过,如果__getattribute__失败, __getattr__被调用。 那么为什么有两种不同的方法做同样的事情呢? 如果我的代码实现了新的风格类,我应该使用什么?

我正在寻找一些代码示例来清除这个问题。 我已经尽力search到了,但是我find的答案并没有彻底讨论这个问题。

如果有任何文件,我准备阅读。

首先是一些基础知识。

有了对象,你需要处理它的属性。 通常我们做instance.attribute 。 有时我们需要更多的控制(当我们不知道属性的名字时)。

例如, instance.attribute将变成getattr(instance, attribute_name) 。 使用这个模型,我们可以通过提供attribute_name作为string来获取属性。

使用__getattr__

您还可以告诉一个类如何处理它没有明确pipe理的属性,并通过__getattr__方法来实现。

只要你请求一个尚未定义的属性,Python就会调用这个方法,所以你可以定义如何处理它。

一个经典用例:

 class A(dict): def __getattr__(self, name): return self[name] a = A() # Now a.somekey will give a['somekey'] 

警告和使用__getattribute__

如果您需要捕获每个属性, 而不pipe它是否存在 ,请改用__getattribute__ 。 不同之处在于__getattr__只被调用了实际不存在的属性。 如果直接设置属性,那么引用该属性将检索它,而不调用__getattr__

__getattribute__被所有的时间调用。

只要属性访问发生,就调用__getattribute__

 class Foo(object): def __init__(self, a): self.a = 1 def __getattribute__(self, attr): try: return self.__dict__[attr] except KeyError: return 'default' f = Foo(1) fa 

这将导致无限recursion。 这里的罪魁祸首是线return self.__dict__[attr] 。 让我们假装(它足够接近真相),所有的属性都存储在self.__dict__并且可以通过它们的名字得到。 该线

 fa 

试图访问fa属性。 这将调用f.__getattribute__('a')__getattribute__然后尝试加载self.__dict____dict__self == f一个属性,所以python调用f.__getattribute__('__dict__') ,它再次尝试访问属性'__dict__ '。 这是无限recursion。

如果__getattr__已经被使用,那么

  1. 它永远不会运行,因为fa属性。
  2. 如果它已经运行了(假设你问了fb ),那么它就不会被调用来查找__dict__因为它已经在那里了,只有在find该属性的所有其他方法都失败时才调用__getattr__

使用__getattribute__编写上述类的“正确”方法是

 class Foo(object): # Same __init__ def __getattribute__(self, attr): return super(Foo, self).__getattribute__(attr) 

super(Foo, self).__getattribute__(attr)将“最近的”超类的__getattribute__方法(forms上是类的方法parsing顺序或MRO中的下一个类super(Foo, self).__getattribute__(attr)绑定到当前对象self ,然后调用它,工作。

所有这些麻烦都可以通过使用__getattr__来避免,它让Python 没有find属性的情况下执行正常的事情 。 在这一点上,Python掌握了你的__getattr__方法,并让它提出一些东西。

还值得注意的是,你可以用__getattr__进入无限recursion。

 class Foo(object): def __getattr__(self, attr): return self.attr 

我会把那个作为一个练习。

我认为其他答案在解释__getattr____getattribute__之间的区别方面做了很多工作,但是有一点可能不清楚,那就是为什么要使用__getattribute__ 。 关于__getattribute__的一个很酷的事情是它实质上允许你在访问一个类的时候重载点。 这使您可以自定义如何在低级别访问属性。 例如,假设我想定义一个只有自我参数的方法被视为属性的类:

 # prop.py import inspect class PropClass(object): def __getattribute__(self, attr): val = super(PropClass, self).__getattribute__(attr) if callable(val): argcount = len(inspect.getargspec(val).args) # Account for self if argcount == 1: return val() else: return val else: return val 

而从互动翻译:

 >>> import prop >>> class A(prop.PropClass): ... def f(self): ... return 1 ... >>> a = A() >>> af 1 

当然这是一个愚蠢的例子,你可能永远不会想这样做,但它显示了你可以从覆盖__getattribute__得到的权力。