编写非数据描述符
问题内容:
我正在学习python中的描述符。我想编写一个非数据描述符,但是以描述符为类__get__
方法的类在调用类方法时不会调用特殊方法。这是我的示例(没有__set__
):
class D(object):
"The Descriptor"
def __init__(self, x = 1395):
self.x = x
def __get__(self, instance, owner):
print "getting", self.x
return self.x
class C(object):
d = D()
def __init__(self, d):
self.d = d
这就是我所说的:
>>> c = C(4)
>>> c.d
4
该__get__
描述符类的就没有得到调用。但是当我还设置一个__set__
描述符时,它似乎被激活了:
class D(object):
"The Descriptor"
def __init__(self, x = 1395):
self.x = x
def __get__(self, instance, owner):
print "getting", self.x
return self.x
def __set__(self, instance, value):
print "setting", self.x
self.x = value
class C(object):
d = D()
def __init__(self, d):
self.d = d
现在,我创建一个C
实例:
>>> c=C(4)
setting 1395
>>> c.d
getting 4
4
并且两者__get__, __set__
都存在。似乎我缺少关于描述符及其使用方法的一些基本概念。谁能解释这种行为__get__, __set__
?
问题答案:
您已经成功创建了正确的非数据描述符,但是随后通过设置实例属性来 屏蔽 该d
属性。
因为它是一个 非
数据描述符,所以实例属性在这种情况下会获胜。添加__set__
方法时,将描述符变成数据描述符,并且即使存在实例属性,也始终应用数据描述符。(*)
从 描述符方法 :
属性访问的默认行为是从对象的字典中获取,设置或删除属性。例如,
a.x
有一个查找链,从a.__dict__['x']
,然后到type(a).__dict__['x']
,并一直到type(a)
排除元类的基类。如果查找到的值是定义描述符方法之一的对象,则Python可能会覆盖默认行为并改为调用描述符方法。优先级链在何处发生取决于定义了哪些描述符方法。
和
如果对象同时定义
__get__()
和__set__()
,则将其视为数据描述符。仅定义__get__()
的描述符称为非数据描述符(它们通常用于方法,但也可以用于其他用途)。数据和非数据描述符的不同之处在于,如何计算实例字典中条目的替代值。如果实例的字典具有与数据描述符同名的条目,则数据描述符优先。如果实例的字典具有与非数据描述符同名的条目,则该字典条目优先。
如果您 删除 的d
实例属性(从来没有对它进行设置或从实例中删除),描述对象被调用:
>>> class D(object):
... def __init__(self, x = 1395):
... self.x = x
... def __get__(self, instance, owner):
... print "getting", self.x
... return self.x
...
>>> class C(object):
... d = D()
...
>>> c = C()
>>> c.d
getting 1395
1395
再次添加一个实例属性,由于实例属性获胜,描述符将被忽略:
>>> c.d = 42 # setting an instance attribute
>>> c.d
42
>>> del c.d # deleting it again
>>> c.d
getting 1395
1395
另请参见Python数据 模型 参考中的 调用描述符
文档
。
__
(*)如果数据描述符实现了__get__
挂钩。 除非 存在于中, 否则
通过访问此类描述符instance.attribute_name
将返回描述符对象。
'attribute_name'``instance.__dict__