首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >了解__getattr__和__getattribute__之间的区别

了解__getattr__和__getattribute__之间的区别
EN

Stack Overflow用户
提问于 2010-11-28 14:23:07
回答 4查看 103.8K关注 0票数 241

我试图理解__getattr____getattribute__之间的区别,然而,我在这方面做得不够好。

堆栈溢出问题的answer 说:

__getattribute__是在查看对象的实际属性之前调用的,因此要正确实现可能很棘手。你可以很容易地在无限递归中结束。

我完全不知道那是什么意思。

然后它继续说:

你几乎肯定想要__getattr__

为什么?

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

我正在寻找一些代码示例来解决这个问题。我已经搜索了我最大的能力,但我找到的答案并没有彻底讨论这个问题。

如果有任何文档,我随时准备阅读。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-11-28 14:55:37

首先是一些基础知识。

对于对象,您需要处理它们的属性。通常,我们使用instance.attribute。有时我们需要更多的控制(当我们事先不知道属性的名称时)。

例如,instance.attribute将变为getattr(instance, attribute_name)。使用此模型,我们可以通过以字符串形式提供attribute_name来获取属性。

__getattr__的使用

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

当您请求一个尚未定义的属性时,Python将调用此方法,因此您可以定义如何处理它。

一个经典的用例:

代码语言:javascript
复制
class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

注意事项和__getattribute__的使用

如果您需要捕获每个属性,而不管它是否存在,请改用__getattribute__。不同之处在于,只为实际不存在的属性调用__getattr__。如果直接设置属性,则引用该属性将在不调用__getattr__的情况下检索它。

__getattribute__总是被调用。

票数 345
EN

Stack Overflow用户

发布于 2010-11-28 15:00:32

每当发生属性访问时,都会调用__getattribute__

代码语言:javascript
复制
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__中,并按其名称可用。这条线

代码语言:javascript
复制
f.a

尝试访问fa属性。这将调用f.__getattribute__('a')。然后,__getattribute__尝试加载self.__dict____dict__self == f的一个属性,因此python调用f.__getattribute__('__dict__'),它再次尝试访问属性'__dict__‘。这是无限递归。

如果使用了__getattr__,那么

  1. 它永远不会运行,因为f有一个它已经运行的a属性(假设您请求了f.b),那么它就不会被调用来查找__dict__,因为它已经存在,并且只有当所有其他查找属性的方法都失败时,才会调用__getattr__

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

代码语言:javascript
复制
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__可能会遇到无限递归。

代码语言:javascript
复制
class Foo(object):
    def __getattr__(self, attr):
        return self.attr

我会把这个作为练习。

票数 110
EN

Stack Overflow用户

发布于 2010-11-28 15:35:08

我认为其他答案已经很好地解释了__getattr____getattribute__之间的区别,但有一件事可能不清楚,那就是为什么要使用__getattribute____getattribute__最酷的一点是,它允许您在访问类时重载点。这允许您自定义如何在较低级别访问属性。例如,假设我想定义一个类,其中只接受self参数的所有方法都被视为属性:

代码语言:javascript
复制
# 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

和来自交互式解释器的:

代码语言:javascript
复制
>>> import prop
>>> class A(prop.PropClass):
...     def f(self):
...             return 1
... 
>>> a = A()
>>> a.f
1

当然,这是一个愚蠢的示例,您可能永远不会想要这样做,但它向您展示了通过覆盖__getattribute__可以获得的强大功能。

票数 63
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4295678

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档