它们都是来自文档的python:
如果对象同时定义
__get__()
和__set__()
,则将其视为数据描述符。 仅定义__get__()
的描述符称为非数据描述符 (它们通常用于方法,但其他用途也是可能的。)
如果描述符定义
__set__()
和/或__delete__()
,则它是数据描述符;如果它既不定义,则它是非数据描述符。 通常,数据描述符定义__get__()
和__set__()
,而非数据描述符只有__get__()
方法。
问题是:仅仅定义__set__
来创建数据描述符是否足够?
我们参考python源代码,我发现了这个:
#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
似乎我们只能在没有__set__
的情况下定义__get__
。
然后我转而写一些例子来证明我得到了什么:
class GetSet(object):
def __get__(self, instance, cls =None):
print('__get__')
def __set__(self, obj, val):
print('__set__')
class Get(object):
def __get__(self, instance, cls =None):
print('__get__')
class Set(object):
def __set__(self, obj, val):
print('__set__')
class UserClass(object):
a = Get()
b = Set()
c = GetSet()
u = UserClass()
u.__dict__['a'] = 'a'
u.__dict__['b'] = 'b'
u.__dict__['c'] = 'c'
print('start')
print(u.a)
print(u.b)
print(u.c)
输出让我再次感到困惑:
start
a
b
__get__
None
根据python属性查找顺序:数据描述符的优先级高于obj.__dict__
。
我的示例显示:只有描述符定义__set__
和__get__
使它成为数据描述符!
哪一个是正确答案?
__set__
--->数据描述符
或
__get__
和__set__
--->数据描述符?
答案 0 :(得分:5)
第二句话是正确的。第二个引用来自Python language reference(尽管您提供了错误的链接),语言参考被认为比操作指南更具权威性。此外,它符合实际行为;您找到的PyDescr_IsData
宏是确定什么算作数据描述符的实际例程used in object.__getattribute__
,either __set__
or __delete__
将导致tp_descr_set
非空。
语言参考还解释了Set
为什么不覆盖a.b
的实例字典的原因:
如果它没有定义
__get__()
,那么访问该属性将返回描述符对象本身,除非对象的实例字典中有值。 [...]定义了__set__()
和__get__()
的数据描述符始终覆盖实例字典中的重新定义。
定义__set__
或__delete__
将设置类型的tp_descr_set
广告位并生成类型数据描述符的实例。即使实例的dict中有一个具有相同名称的条目,即使它只有__set__
并且你是&{&}},也会始终调用数据描述符来尝试设置或删除它管理的属性。 #39;尝试删除属性,反之亦然。 (如果它没有所需的方法,则会引发异常。)如果数据描述符也有__get__
,它也会拦截获取属性的尝试;否则,Python将依赖于正常的属性查找行为,就好像它根本就不是描述符。