我正在学习python中的描述符。我想写一个非数据描述符,但是当我调用classmethod时,具有描述符作为其类方法的类不会调用__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__
的这种行为吗?
答案 0 :(得分:9)
您已成功创建了正确的非数据描述符,但您可以通过设置实例属性掩盖 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 Datamodel 参考中的Invoking Descriptors documentation。