Python 了解 __getattr__ 和 __getattribute__ 之间的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4295678/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding the difference between __getattr__ and __getattribute__
提问by user225312
I am trying to understand the difference between __getattr__and __getattribute__, however, I am failing at it.
我试图理解上的差异之间__getattr__和__getattribute__,但是,我在它失败。
The answerto the Stack Overflow question Difference between __getattr__vs __getattribute__says:
Stack Overflow 问题的答案vs之间的差异__getattr____getattribute__说:
__getattribute__is invoked before looking at the actual attributes on the object, and so can be tricky to implement correctly. You can end up in infinite recursions very easily.
__getattribute__在查看对象的实际属性之前调用,因此正确实现可能会很棘手。您可以很容易地以无限递归结束。
I have absolutely no idea what that means.
我完全不知道这意味着什么。
Then it goes on to say:
然后接着说:
You almost certainly want
__getattr__.
你几乎肯定想要
__getattr__。
Why?
为什么?
I read that if __getattribute__fails, __getattr__is called. So why are there two different methods doing the same thing? If my code implements the new style classes, what should I use?
我读到如果__getattribute__失败,__getattr__则调用。那么为什么有两种不同的方法做同样的事情呢?如果我的代码实现了新的样式类,我应该使用什么?
I am looking for some code examples to clear this question. I have Googled to best of my ability, but the answers that I found don't discuss the problem thoroughly.
我正在寻找一些代码示例来解决这个问题。我已尽我所能在谷歌上搜索,但我找到的答案并没有彻底讨论这个问题。
If there is any documentation, I am ready to read that.
如果有任何文档,我准备阅读。
采纳答案by pyfunc
Some basics first.
先说一些基础知识。
With objects, you need to deal with its attributes. Ordinarily we do instance.attribute. Sometimes we need more control (when we do not know the name of the attribute in advance).
对于对象,您需要处理其属性。通常我们会这样做instance.attribute。有时我们需要更多的控制(当我们事先不知道属性的名称时)。
For example, instance.attributewould become getattr(instance, attribute_name). Using this model, we can get the attribute by supplying the attribute_nameas a string.
例如,instance.attribute会变成getattr(instance, attribute_name). 使用此模型,我们可以通过将attribute_name作为字符串提供来获取属性。
Use of __getattr__
用于 __getattr__
You can also tell a class how to deal with attributes which it doesn't explicitly manage and do that via __getattr__method.
您还可以告诉一个类如何处理它没有明确管理的属性,并通过__getattr__方法来处理。
Python will call this method whenever you request an attribute that hasn't already been defined, so you can define what to do with it.
每当您请求尚未定义的属性时,Python 都会调用此方法,因此您可以定义如何处理它。
A classic use case:
一个经典用例:
class A(dict):
def __getattr__(self, name):
return self[name]
a = A()
# Now a.somekey will give a['somekey']
Caveats and use of __getattribute__
注意事项和使用 __getattribute__
If you need to catch every attribute regardless whether it exists or not, use __getattribute__instead. The difference is that __getattr__only gets called for attributes that don't actually exist. If you set an attribute directly, referencing that attribute will retrieve it without calling __getattr__.
如果您需要捕获每个属性,而不管它是否存在,请__getattribute__改用。不同之处在于,__getattr__只有实际不存在的属性才会被调用。如果您直接设置属性,则引用该属性将检索它而不调用__getattr__.
__getattribute__is called all the times.
__getattribute__一直被称为。
回答by aaronasterling
__getattribute__is called whenever an attribute access occurs.
__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
This will cause infinite recursion. The culprit here is the line return self.__dict__[attr]. Let's pretend (It's close enough to the truth) that all attributes are stored in self.__dict__and available by their name. The line
这将导致无限递归。这里的罪魁祸首是线路return self.__dict__[attr]。让我们假设(这已经足够接近事实了)所有属性都存储在其中self.__dict__并通过其名称可用。线
f.a
attempts to access the aattribute of f. This calls f.__getattribute__('a'). __getattribute__then tries to load self.__dict__. __dict__is an attribute of self == fand so python calls f.__getattribute__('__dict__')which again tries to access the attribute '__dict__'. This is infinite recursion.
尝试访问 的a属性f。这叫f.__getattribute__('a'). __getattribute__然后尝试加载self.__dict__. __dict__是一个属性,self == f因此 python 调用f.__getattribute__('__dict__')再次尝试访问属性'__dict__'. 这是无限递归。
If __getattr__had been used instead then
如果__getattr__已经被使用,那么
- It never would have run because
fhas anaattribute. - If it had run, (let's say that you asked for
f.b) then it would not have been called to find__dict__because it's already there and__getattr__is invoked only if all other methods of finding the attribute have failed.
- 它永远不会运行,因为它
f有一个a属性。 - 如果它已运行(假设您要求
f.b),则不会调用__dict__它来查找,因为它已经存在并且__getattr__仅在查找属性的所有其他方法都失败时才调用。
The 'correct' way to write the above class using __getattribute__is
使用编写上述类的“正确”方法__getattribute__是
class Foo(object):
# Same __init__
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
super(Foo, self).__getattribute__(attr)binds the __getattribute__method of the 'nearest' superclass (formally, the next class in the class's Method Resolution Order, or MRO) to the current object selfand then calls it and lets that do the work.
super(Foo, self).__getattribute__(attr)将__getattribute__“最近的”超类(正式地,类的方法解析顺序中的下一个类,或 MRO)的方法绑定到当前对象self,然后调用它并让其完成工作。
All of this trouble is avoided by using __getattr__which lets Python do it's normal thinguntil an attribute isn't found. At that point, Python hands control over to your __getattr__method and lets it come up with something.
所有这些麻烦都__getattr__可以通过使用which 让 Python做它正常的事情来避免,直到找不到属性。在这一点上,Python 将控制权交给您的__getattr__方法并让它想出一些东西。
It's also worth noting that you can run into infinite recursion with __getattr__.
还值得注意的是,您可能会遇到无限递归__getattr__。
class Foo(object):
def __getattr__(self, attr):
return self.attr
I'll leave that one as an exercise.
我将把它留作练习。
回答by Jason Baker
I think the other answers have done a great job of explaining the difference between __getattr__and __getattribute__, but one thing that might not be clear is why you would want to use __getattribute__. The cool thing about __getattribute__is that it essentially allows you to overload the dot when accessing a class. This allows you to customize how attributes are accessed at a low level. For instance, suppose I want to define a class where all methods that only take a self argument are treated as properties:
我认为其他的答案做了解释之间的差异的一个伟大的工作__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
And from the interactive interpreter:
来自交互式解释器:
>>> import prop
>>> class A(prop.PropClass):
... def f(self):
... return 1
...
>>> a = A()
>>> a.f
1
Of course this is a silly example and you probably wouldn't ever want to do this, but it shows you the power you can get from overriding __getattribute__.
当然,这是一个愚蠢的例子,您可能永远不想这样做,但它向您展示了您可以从覆盖__getattribute__.
回答by mathsyouth
I have gone through other's excellent explanation. However, I found a simple answer from this blog Python Magic Methods and __getattr__. All the following are from there.
我已经经历了其他人的出色解释。但是,我从这篇博客Python Magic Methods 和__getattr__. 以下所有内容均来自那里。
Using the __getattr__magic method, we can intercept that inexistent attribute lookup and do something so it doesn't fail:
使用__getattr__魔术方法,我们可以拦截不存在的属性查找并做一些事情,使其不会失败:
class Dummy(object):
def __getattr__(self, attr):
return attr.upper()
d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE'
But if the attribute does exist, __getattr__won't be invoked:
但如果该属性确实存在,__getattr__则不会被调用:
class Dummy(object):
def __getattr__(self, attr):
return attr.upper()
d = Dummy()
d.value = "Python"
print(d.value) # "Python"
__getattribute__is similar to __getattr__, with the important difference that __getattribute__will intercept EVERYattribute lookup, doesn't matter if the attribute exists or not.
__getattribute__与 类似__getattr__,重要的区别是__getattribute__将拦截每个属性查找,无论该属性是否存在都无关紧要。
class Dummy(object):
def __getattribute__(self, attr):
return 'YOU SEE ME?'
d = Dummy()
d.value = "Python"
print(d.value) # "YOU SEE ME?"
In that example, the dobject already has an attribute value. But when we try to access it, we don't get the original expected value (“Python”); we're just getting whatever __getattribute__returned. It means that we've virtually lost the value attribute; it has become “unreachable”.
在那个例子中,d对象已经有一个属性值。但是当我们尝试访问它时,我们并没有得到最初的期望值(“Python”);我们只是得到任何__getattribute__回报。这意味着我们实际上已经失去了 value 属性;它变得“遥不可及”。

