了解__getattr__和__getattribute__之间的区别
我想了解__getattr__
和__getattribute__
之间的区别,但是,我失败了。
堆栈溢出问题getattr与getattribute之间的区别说,
在查看对象上的实际属性之前调用
__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
试图访问f
的a
属性。 这将调用f.__getattribute__('a')
。 __getattribute__
然后尝试加载self.__dict__
。 __dict__
是self == f
一个属性,所以python调用f.__getattribute__('__dict__')
,它再次尝试访问属性'__dict__
'。 这是无限recursion。
如果__getattr__
已经被使用,那么
- 它永远不会运行,因为
f
有a
属性。 - 如果它已经运行了(假设你问了
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__
得到的权力。