哪一个是数据描述符和非数据描述符的正确定义?

时间:2015-05-19 01:12:43

标签: python python-3.4

它们都是来自文档的python:

the first one说:

  

如果对象同时定义__get__()__set__(),则将其视为数据描述符。   仅定义__get__()的描述符称为非数据描述符       (它们通常用于方法,但其他用途也是可能的。)

the second one说:

  

如果描述符定义__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__ --->数据描述符?

1 个答案:

答案 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将依赖于正常的属性查找行为,就好像它根本就不是描述符。