哪个是数据描述符和非数据描述符的正确定义?
which one is the right definition of data-descriptor and non-data descriptor?
他们都是python来自文档:
If an object defines both __get__()
and __set__()
, it is considered a data descriptor.
Descriptors that only define__get__()
are called non-data descriptors
(they are typically used for methods but other uses are possible).
If the descriptor defines __set__()
and/or __delete__()
, it is a data descriptor; if it defines neither, it is a non-data descriptor.
Normally, data descriptors define both __get__()
and __set__()
, while non-data descriptors have just the __get__()
method.
问题是:仅定义 __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__
---> 数据描述符 ?
第二个引用是正确的。第二个引号来自 Python language reference (though you've provided the wrong link), and the language reference is considered more authoritative than how-to guides. Also, it matches the actual behavior; the PyDescr_IsData
macro you found is the actual routine used in object.__getattribute__
to determine what counts as a data descriptor, and either __set__
or __delete__
将导致 tp_descr_set
为非空。
语言参考还解释了为什么 Set
不覆盖 a.b
:
的实例字典
If it does not define __get__()
, then accessing the attribute will return the descriptor object itself unless there is a value in the object’s instance dictionary. [...] Data descriptors with __set__()
and __get__()
defined always override a redefinition in an instance dictionary.
定义 __set__
或 __delete__
将设置类型的 tp_descr_set
槽并生成类型数据描述符的实例。数据描述符将始终被调用以尝试设置或删除它管理的属性,即使实例的字典中有一个具有相同名称的条目,即使它只有 __set__
而你正在尝试删除属性,反之亦然。 (如果它没有所需的方法,它会引发异常。)如果数据描述符也有 __get__
,它也会拦截获取属性的尝试;否则,Python 将退回到正常的属性查找行为,就好像它根本不是描述符一样。
他们都是python来自文档:
If an object defines both
__get__()
and__set__()
, it is considered a data descriptor. Descriptors that only define__get__()
are called non-data descriptors (they are typically used for methods but other uses are possible).
If the descriptor defines
__set__()
and/or__delete__()
, it is a data descriptor; if it defines neither, it is a non-data descriptor. Normally, data descriptors define both__get__()
and__set__()
, while non-data descriptors have just the__get__()
method.
问题是:仅定义 __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__
---> 数据描述符 ?
第二个引用是正确的。第二个引号来自 Python language reference (though you've provided the wrong link), and the language reference is considered more authoritative than how-to guides. Also, it matches the actual behavior; the PyDescr_IsData
macro you found is the actual routine used in object.__getattribute__
to determine what counts as a data descriptor, and either __set__
or __delete__
将导致 tp_descr_set
为非空。
语言参考还解释了为什么 Set
不覆盖 a.b
:
If it does not define
__get__()
, then accessing the attribute will return the descriptor object itself unless there is a value in the object’s instance dictionary. [...] Data descriptors with__set__()
and__get__()
defined always override a redefinition in an instance dictionary.
定义 __set__
或 __delete__
将设置类型的 tp_descr_set
槽并生成类型数据描述符的实例。数据描述符将始终被调用以尝试设置或删除它管理的属性,即使实例的字典中有一个具有相同名称的条目,即使它只有 __set__
而你正在尝试删除属性,反之亦然。 (如果它没有所需的方法,它会引发异常。)如果数据描述符也有 __get__
,它也会拦截获取属性的尝试;否则,Python 将退回到正常的属性查找行为,就好像它根本不是描述符一样。