了解 __getattr__ 和 __getattribute__ 之间的区别
我试图理解 __getattr__ 和 __getattribute__ 之间的区别,但是,我失败了。
Stack Overflow 问题的答案__getattr__
与 __getattribute__
之间的差异说:
__getattribute__
在查看实际属性之前被调用 对象,因此可能很难 正确实施。你最终可能会进入 无限递归非常容易。
我完全不知道这意味着什么。
然后它接着说:
您几乎肯定需要
__getattr__
。
为什么?
我读到,如果 __getattribute__ 失败,则会调用 __getattr__ 。那么为什么有两种不同的方法做同样的事情呢?如果我的代码实现了新样式的类,我应该使用什么?
我正在寻找一些代码示例来解决这个问题。我已尽我所能在谷歌上搜索,但我找到的答案并没有彻底讨论这个问题。
如果有任何文档,我准备阅读。
I am trying to understand the difference between __getattr__
and __getattribute__
, however, I am failing at it.
The answer to the Stack Overflow question Difference between __getattr__
vs __getattribute__
says:
__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.
I have absolutely no idea what that means.
Then it goes on to say:
You almost certainly want
__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?
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先是一些基础知识。
对于对象,您需要处理它们的属性。通常,我们使用
instance.attribute
。有时我们需要更多的控制(当我们事先不知道属性的名称时)。例如,
instance.attribute
将变为getattr(instance, attribute_name)
。使用此模型,我们可以通过以字符串形式提供attribute_name来获取属性。使用
__getattr__
您还可以告诉类如何处理它未显式管理的属性,并通过
__getattr__
方法来执行此操作。每当您请求尚未定义的属性时,Python 都会调用此方法,以便您可以定义如何处理它。
经典用例:
注意事项和
__getattribute__
的使用如果您需要捕获每个属性,无论它是否存在,请改用
__getattribute__
。不同之处在于,仅针对实际不存在的属性调用__getattr__
。如果直接设置属性,则引用该属性将检索它,而无需调用 __getattr__ 。__getattribute__
始终被调用。Some basics first.
With objects, you need to deal with their attributes. Ordinarily, we do
instance.attribute
. Sometimes we need more control (when we do not know the name of the attribute in advance).For example,
instance.attribute
would becomegetattr(instance, attribute_name)
. Using this model, we can get the attribute by supplying the attribute_name as a string.Use of
__getattr__
You can also tell a class how to deal with attributes which it doesn't explicitly manage and do that via
__getattr__
method.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.
A classic use case:
Caveats and use of
__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__
is called all the times.每当发生属性访问时都会调用 __getattribute__ 。
这将导致无限递归。这里的罪魁祸首是 return self.__dict__[attr] 行。让我们假设(这与事实足够接近)所有属性都存储在 self.__dict__ 中,并且可以通过它们的名称来访问。该行
尝试访问
f
的a
属性。这会调用f.__getattribute__('a')
。__getattribute__
然后尝试加载self.__dict__
。__dict__
是self == f
的一个属性,因此 python 调用f.__getattribute__('__dict__')
,它再次尝试访问属性 <代码>'__dict__'。这就是无限递归。如果使用
__getattr__
,那么f
有一个a
属性。fb
),则不会调用它来查找__dict__
,因为它已经存在并且__getattr__
> 仅当查找属性的所有其他方法均失败时才会调用。使用
__getattribute__
编写上述类的“正确”方法是super().__getattribute__(attr)
绑定“最近的”的__getattribute__
方法' 超类(正式地,类的方法解析顺序中的下一个类,或 MRO)到当前对象self
,然后调用它并让它完成工作。所有这些麻烦都可以通过使用
__getattr__
来避免,它让 Python 做正常的事情,直到找不到属性。此时,Python 将控制权交给您的__getattr__
方法并让它提出一些建议。还值得注意的是,您可能会使用
__getattr__
遇到无限递归。我会把那个作为练习。
__getattribute__
is called whenever an attribute access occurs.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 inself.__dict__
and available by their name. The lineattempts to access the
a
attribute off
. This callsf.__getattribute__('a')
.__getattribute__
then tries to loadself.__dict__
.__dict__
is an attribute ofself == f
and so python callsf.__getattribute__('__dict__')
which again tries to access the attribute'__dict__
'. This is infinite recursion.If
__getattr__
had been used instead thenf
has ana
attribute.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.The 'correct' way to write the above class using
__getattribute__
issuper().__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 objectself
and then calls it and lets that do the work.All of this trouble is avoided by using
__getattr__
which lets Python do it's normal thing until an attribute isn't found. At that point, Python hands control over to your__getattr__
method and lets it come up with something.It's also worth noting that you can run into infinite recursion with
__getattr__
.I'll leave that one as an exercise.
我认为其他答案已经很好地解释了
__getattr__
和__getattribute__
之间的区别,但可能不清楚的一件事是为什么你想要使用>__getattribute__
。__getattribute__
的一个很酷的事情是,它本质上允许您在访问类时重载点。这允许您自定义如何在低级别访问属性。例如,假设我想定义一个类,其中所有仅接受 self 参数的方法都被视为属性:并且来自交互式解释器:
当然这是一个愚蠢的示例,您可能永远不想这样做,但是它向您展示了通过重写 __getattribute__ 可以获得的强大功能。
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:And from the interactive interpreter:
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__
.我已经阅读了其他人的精彩解释。但是,我从这个博客 Python 魔法方法和
找到了一个简单的答案__getattr__
。以下所有内容均来自那里。使用 __getattr__ 魔术方法,我们可以拦截不存在的属性查找并执行某些操作,以免失败:
但是如果该属性确实存在,则不会调用 __getattr__ :
__getattribute__
与__getattr__
类似,重要的区别是__getattribute__
将拦截 EVERY 属性查找,但不会该属性是否存在无关紧要。在该示例中,
d
对象已经具有属性值。但是当我们尝试访问它时,我们没有得到原始的期望值(“Python”);我们只是得到返回的任何__getattribute__
。这意味着我们实际上已经失去了价值属性;它已经变得“遥不可及”。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.Using the
__getattr__
magic method, we can intercept that inexistent attribute lookup and do something so it doesn’t fail:But if the attribute does exist,
__getattr__
won’t be invoked:__getattribute__
is similar to__getattr__
, with the important difference that__getattribute__
will intercept EVERY attribute lookup, doesn’t matter if the attribute exists or not.In that example, the
d
object 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”.