我试图理解__getattr__
和__getattribute__
之间的区别,但是,我失败了。
堆栈溢出问题 * Difference between __getattr__
vs __getattribute__
* 的answer表示:__getattribute__
是在查看对象的实际属性之前调用的,因此要正确实现它可能很棘手,很容易导致无限递归。
我完全不知道那是什么意思。
然后它继续说:
你几乎肯定想要__getattr__
。
为什么?
我读到如果__getattribute__
失败,__getattr__
被调用。那么为什么有两个不同的方法做同样的事情?如果我的代码实现了新样式的类,我应该使用什么?
我正在寻找一些代码的例子,以明确这个问题。我已经谷歌我的能力,但我发现的答案没有彻底讨论这个问题。
如果有任何文件,我准备阅读。
4条答案
按热度按时间holgip5t1#
我已经看过了别人的精彩解释,但是我在这个博客Python Magic Methods and
__getattr__
上找到了一个简单的答案。以下都是从那里来的。使用
__getattr__
magic方法,我们可以拦截不存在的属性查找,并执行一些操作,使其不会失败:但如果属性确实存在,则不会调用
__getattr__
:__getattribute__
类似于__getattr__
,重要的区别在于__getattribute__
将拦截EVERY属性查找,而不管属性是否存在。在那个例子中,
d
对象已经有了一个属性值,但是当我们试图访问它时,我们没有得到原来期望的值(“Python”);我们只是得到了__getattribute__
返回的值,这意味着我们实际上丢失了value属性;它就变得“不可达”。goqiplq22#
先来点基础知识。
对于对象,你需要处理它们的属性,通常我们是
instance.attribute
,有时候我们需要更多的控制(当我们事先不知道属性的名称时)。例如,
instance.attribute
将变为getattr(instance, attribute_name)
,使用这个模型,我们可以通过提供字符串形式的 attribute_name 来获取属性。使用
__getattr__
你也可以告诉一个类如何处理它没有显式管理的属性,并通过
__getattr__
方法来完成。每当你请求一个尚未定义的属性时,Python都会调用这个方法,所以你可以定义如何处理它。
经典使用案例:
__getattribute__
的使用和注意事项如果你需要捕获每个属性 * 而不管它是否存在 *,那么使用
__getattribute__
代替。不同之处在于__getattr__
只被调用用于实际上不存在的属性。如果你直接设置一个属性,引用该属性将在不调用__getattr__
的情况下检索它。__getattribute__
一直被调用。mwngjboj3#
只要发生属性访问,就调用
__getattribute__
。这将导致无限递归。罪魁祸首是
return self.__dict__[attr]
行。让我们假设(这足够接近事实)所有属性都存储在self.__dict__
中,并且可以通过它们的名称获得。尝试访问
f
的a
属性。这将调用f.__getattribute__('a')
。__getattribute__
,然后尝试加载self.__dict__
。__dict__
是self == f
的属性,因此python调用f.__getattribute__('__dict__')
,f.__getattribute__('__dict__')
将再次尝试访问属性'__dict__
'。这是无限递归。如果使用的是
__getattr__
,则1.因为
f
具有a
属性,所以它永远不会运行。1.如果它已经运行了,(假设你要求
f.b
)那么它就不会被调用来查找__dict__
,因为它已经存在了,并且__getattr__
只有在 * 所有其他查找属性的方法都失败了 * 的情况下才会被调用。使用
__getattribute__
编写上述类的“正确”方法是super().__getattribute__(attr)
将“最近的”超类(形式上,类的方法解析顺序或MRO中的下一个类)的__getattribute__
方法绑定到当前对象self
,然后调用它并让它完成工作。所有这些麻烦都可以通过使用
__getattr__
来避免,它让Python * 做它的正常事情 *,直到一个属性找不到为止。在这一点上,Python将控制权交给你的__getattr__
方法,并让它产生一些东西。同样值得注意的是,使用
__getattr__
可能会遇到无限递归。我就把这个当作练习吧。
fjnneemd4#
我认为其他的答案已经很好地解释了
__getattr__
和__getattribute__
之间的区别,但是有一件事可能不太清楚,那就是为什么要使用__getattribute__
。__getattribute__
的酷之处在于,它本质上允许您在访问类时重载点。这允许您在低级别定制如何访问属性。例如,假设我想定义一个类,其中所有只接受self参数的方法都被视为属性:在交互式解释器中:
当然,这是一个愚蠢的例子,您可能永远不会想这样做,但它向您展示了通过重写
__getattribute__
可以获得的强大功能。