【发布时间】:2019-05-17 00:01:43
【问题描述】:
This article 描述了 Python 在执行 o.a 时如何查找对象的属性。优先顺序很有趣 - 它查找:
- 作为数据描述符的类属性(最常见的是属性)
- 实例属性
- 任何其他类属性
我们可以使用下面的代码来确认这一点,它创建了一个对象o,其实例属性为a,其类包含一个同名的属性:
class C:
def __init__(self):
self.__dict__['a'] = 1
@property
def a(self):
return 2
o = C()
print(o.a) # Prints 2
为什么 Python 使用这种优先顺序而不是“幼稚”顺序(实例属性优先于所有类属性)? Python 的优先级顺序有一个显着的缺点:它使属性查找变慢,因为不是只返回 o 的属性(如果存在)(常见情况),Python 必须首先搜索 o 的类 及其所有数据描述符的超类。
Python 的优先顺序有什么好处?这可能不仅仅是针对上述情况,因为拥有一个实例变量和一个同名的属性是非常极端的情况(注意需要使用self.__dict__['a'] = 1 来创建实例属性,因为通常的self.a = 1 会调用属性)。
是否存在“天真的”查找顺序会导致问题的不同情况?
【问题讨论】:
-
AFAICT JavaScript 使用“幼稚”的查找顺序并且工作正常。以下代码,等效于 Python 示例,打印
1:class C { constructor() { Object.defineProperty(this, 'a', {value: 1}); } get a() { return 2; } }var o = new C(); console.log(o.a); -
我是否正确理解“为什么 Python 中存在数据描述符?”你的问题归结为什么?您是否知道您可以通过编写描述符类来编写自己的非数据描述符“属性”?
-
@timgeb - AFAIK 数据描述符(同时具有
__get__和__set__的描述符)主要用于支持属性。我想知道的是,为什么数据描述符优先于实例属性? -
我假设是因为这是确保您的 getter 逻辑运行的一种方式。
-
我是这样看的:数据描述符是默认情况。当我有一个
__get__和一个__set__方法时,我希望这些钩子触发,而不管对象的__dict__中是否存在相关属性的细节。如果属性不在__dict__中,那么您希望getter 仅触发的特殊情况下使用非数据描述符。例如,非数据描述符非常适合__get__ting 一次值,然后将其缓存在实例__dict__中。
标签: python oop properties descriptor