每个对象都有一个属性字典,其中包含它的变量和函数。参考这些词典:
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__,直到创建了同名的实例变量。