如何了解__getattr__和__getattribute__之间的区别?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (51)

我试图理解上的差异之间__getattr____getattribute__

堆栈溢出问题getattrgetattribute之间的区别说,

__getattribute__在查看对象的实际属性之前调用,因此可能会很难正确实现。您可以非常轻松地以无限递归结束。

我完全不知道这意味着什么。

然后它继续说:

你几乎肯定想要__getattr__

为什么?

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

我正在寻找一些代码示例来清除此问题。我已尽最大努力去搜索,但我找到的答案并没有彻底讨论这个问题。

提问于
用户回答回答于

首先是一些基础知识。

有了对象,你需要处理它的属性。我们通常会这样做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__ 被称为所有的时间。

用户回答回答于

__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

试图访问的a属性f。这个电话f.__getattribute__('a')__getattribute__然后尝试加载self.__dict____dict__self == fpython调用的属性,f.__getattribute__('__dict__')它再次尝试访问该属性'__dict__'。这是无限递归。

如果__getattr__已经被使用,那么

  1. 它永远不会运行,因为f有一个a属性。
  2. 如果它已经运行了(假设你要求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__“最近的”超类的方法(形式上,类的方法解析顺序或MRO中的下一个类)绑定到当前对象self,然后调用它并让它完成工作。

所有这些麻烦都__getattr__可以通过使用它来避免,因为在没有找到属性之前,Python 可以正常工作。在这一点上,Python会控制你的__getattr__方法,并让它提供一些东西。

还值得注意的是,你可以用无限递归运行__getattr__

class Foo(object):
    def __getattr__(self, attr):
        return self.attr

扫码关注云+社区