Python中数据描述符的优先级是如何工作的?
我在网上看到了一些内容
对于对象来说,背后的机制在于
object.__getattribute__
,它会把b.x
转换成type(b).__dict__['x'].__get__(b, type(b)).
这个实现通过一个优先级链来工作,给数据描述符比实例变量更高的优先级,而实例变量又比非数据描述符优先级高,如果有提供 getattr,它的优先级最低。
我不太明白“给数据描述符比实例变量更高的优先级”和“实例变量比非数据描述符优先级高”是什么意思
有没有人能给我一个例子,看看在代码中哪个东西的优先级更高
1 个回答
每个对象都有一个属性字典,这个字典里包含了它的变量和函数。提到这些字典时:
If an instance’s dictionary has an entry with the same name as a data descriptor,
the data descriptor takes precedence. If an instance’s dictionary has an entry with
the same name as a non-data descriptor, the dictionary entry takes precedence.
这就是他们在说的内容。
为了展示这一点:
#data descriptor
class A(object):
def __get__(self, obj, type):
print "hello from get A"
def __set__(self, obj, val):
print "hello from set A"
#non data descriptor
class B(object):
def __get__(self, obj, type):
print "hello from get B"
class C(object):
#our data descriptor
a = A()
#our non data descriptor
b = B()
>>> c = C()
>>> c.a
hello from get A
>>> c.b
hello from get B
>>> c.a = 0
hello from set A
>>> c.a #notice after reassignment, A.__get__ is still called
hello from set A
>>> c.b = 0 #instance variable with the same name as the non data-descriptor
>>> c.b #notice how B.__get__ isn't called anymore
0
基本上,这段话的意思是,当你为一个对象自定义了 __get__
和 __set__
方法(这叫做数据描述符),那么在访问或修改属性时,就会调用你自定义的方法,而不是默认的方法。如果只自定义了 __get__
方法(这叫做非数据描述符),那么实例可以重新赋值给一个实例变量。
举个例子,当你执行 g.x = 0
时:如果 x 是一个数据描述符,那么就会调用 x 自定义的 __set__
方法;如果 x 是一个实例变量或者非数据描述符,那么就会调用默认的行为。
对于数据描述符来说,类会控制对变量的所有访问和修改。所有对数据描述符类型变量的访问都会经过 __get__
和 __set__
方法。所以当你执行 c.a = 0
时,会调用 A.__set__
,并且 c.a 的值会按照类定义的方式被改变。你无法创建一个不是类型 A 的实例变量 'c.a'。
而对于非数据描述符来说,类只控制访问,所以当你执行 c.b = 0
时,由于没有定义 __set__
,就会创建一个新的实例变量(这是默认行为)。在设置变量时没有自定义的行为,因此你可以创建一个同名的实例变量,而不需要 __get__
的行为。
他们提到的优先级是指这两者的动态关系。数据描述符会始终调用 __get__
和 __set__
,因此无法创建同名的实例变量。而非数据描述符只会在创建同名的实例变量之前调用 __get__
。