我试图理解__getattr__
和__getattribute__
之间的区别,然而,我在这方面做得不够好。
堆栈溢出问题的answer 说:
__getattribute__
是在查看对象的实际属性之前调用的,因此要正确实现可能很棘手。你可以很容易地在无限递归中结束。
我完全不知道那是什么意思。
然后它继续说:
你几乎肯定想要
__getattr__
。
为什么?
我读到如果__getattribute__
失败,就会调用__getattr__
。那么为什么会有两种不同的方法做同样的事情呢?如果我的代码实现了新的样式类,我应该使用什么?
我正在寻找一些代码示例来解决这个问题。我已经搜索了我最大的能力,但我找到的答案并没有彻底讨论这个问题。
如果有任何文档,我随时准备阅读。
发布于 2010-11-28 14:55:37
首先是一些基础知识。
对于对象,您需要处理它们的属性。通常,我们使用instance.attribute
。有时我们需要更多的控制(当我们事先不知道属性的名称时)。
例如,instance.attribute
将变为getattr(instance, attribute_name)
。使用此模型,我们可以通过以字符串形式提供attribute_name来获取属性。
__getattr__
的使用
您还可以告诉一个类如何处理它没有显式管理的属性,并通过__getattr__
方法来实现。
当您请求一个尚未定义的属性时,Python将调用此方法,因此您可以定义如何处理它。
一个经典的用例:
class A(dict):
def __getattr__(self, name):
return self[name]
a = A()
# Now a.somekey will give a['somekey']
注意事项和__getattribute__
的使用
如果您需要捕获每个属性,而不管它是否存在,请改用__getattribute__
。不同之处在于,只为实际不存在的属性调用__getattr__
。如果直接设置属性,则引用该属性将在不调用__getattr__
的情况下检索它。
__getattribute__
总是被调用。
发布于 2010-11-28 15:00:32
每当发生属性访问时,都会调用__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)
f.a
这将导致无限递归。这里的罪魁祸首是return self.__dict__[attr]
行。让我们假设(这与事实非常接近)所有属性都存储在self.__dict__
中,并按其名称可用。这条线
f.a
尝试访问f
的a
属性。这将调用f.__getattribute__('a')
。然后,__getattribute__
尝试加载self.__dict__
。__dict__
是self == f
的一个属性,因此python调用f.__getattribute__('__dict__')
,它再次尝试访问属性'__dict__
‘。这是无限递归。
如果使用了__getattr__
,那么
f
有一个它已经运行的a
属性(假设您请求了f.b
),那么它就不会被调用来查找__dict__
,因为它已经存在,并且只有当所有其他查找属性的方法都失败时,才会调用__getattr__
。使用__getattribute__
编写上述类的“正确”方法是
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)
将“最近”超类的__getattribute__
方法(正式地说,是该类的方法解析顺序中的下一个类)绑定到当前的对象self
,然后调用它,让它来完成这项工作。
所有这些麻烦都可以通过使用__getattr__
来避免,它让Python做一些正常的事情,直到找不到属性为止。在这一点上,Python将控制权交给您的__getattr__
方法,并让它提供一些东西。
同样值得注意的是,使用__getattr__
可能会遇到无限递归。
class Foo(object):
def __getattr__(self, attr):
return self.attr
我会把这个作为练习。
发布于 2010-11-28 15:35:08
我认为其他答案已经很好地解释了__getattr__
和__getattribute__
之间的区别,但有一件事可能不清楚,那就是为什么要使用__getattribute__
。__getattribute__
最酷的一点是,它允许您在访问类时重载点。这允许您自定义如何在较低级别访问属性。例如,假设我想定义一个类,其中只接受self参数的所有方法都被视为属性:
# 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()
>>> a.f
1
当然,这是一个愚蠢的示例,您可能永远不会想要这样做,但它向您展示了通过覆盖__getattribute__
可以获得的强大功能。
https://stackoverflow.com/questions/4295678
复制相似问题