问题描述
它们都是来自文档的python:
Both of them are python from documents :
第一个说:
如果一个对象同时定义了 __get__()
和 __set__()
,它被认为是一个数据描述符.只定义__get__()
的描述符被称为非数据描述符(它们通常用于方法,但也可以用于其他用途).
第二个说:
如果描述符定义了__set__()
和/或__delete__()
,则为数据描述符;如果两者都没有定义,则它是一个非数据描述符.通常,数据描述符同时定义了 __get__()
和 __set__()
,而非数据描述符只有 __get__()
方法.
问题是:只定义__set__
来制作数据描述符就够了吗?
The question is : is it enough to only define __set__
to make a data descriptor ?
我们参考了python源代码,我发现了这个:
And we I refer to the python source code, I found this :
#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
似乎我们只能定义 __set__
而没有 __get__
.
Seems we can only define __set__
without __get__
.
然后我转而写一些例子来证明我得到了什么:
And then I turn to write some examples to prove what I got :
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__
.
According to the python attribute lookup orders : the priority of data descriptor is higher than obj.__dict__
.
我的示例显示:只有描述符同时定义了 __set__
和 __get__
使其成为数据描述符!
My example shows : Only the descriptor defines both __set__
and __get__
makes it a data descriptor !
哪个是正确答案?
__set__
--- > 数据描述符
__set__
--- > data descriptor
或
__get__
和 __set__
---> 数据描述符 ?
__get__
and __set__
---> data descriptor ?
推荐答案
第二个引用是正确的.第二个引用来自 Python 语言参考(虽然你'提供了错误的链接),并且语言参考被认为比操作指南更权威.此外,它与实际行为相匹配;PyDescr_IsData
宏你发现的是在object中使用的实际例程.__getattribute__
确定什么算作数据描述符,以及 无论是 __set__
还是 __delete__
都会导致 tp_descr_set
为非空.
The second quote is correct. The second quote comes from the 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__
will cause tp_descr_set
to be non-null.
语言参考还解释了为什么 Set
不会覆盖 a.b
的实例字典:
The language reference also explains why Set
doesn't override the instance dict for a.b
:
如果它没有定义__get__()
,那么访问该属性将返回描述符对象本身,除非该对象的实例字典中有一个值.[...] 定义了 __set__()
和 __get__()
的数据描述符总是覆盖实例字典中的重定义.
定义 __set__
或 __delete__
将设置类型的 tp_descr_set
槽并创建类型数据描述符的实例.数据描述符将始终被调用以尝试设置或删除它管理的属性,即使实例的 dict 中有一个具有相同名称的条目,即使它只有 __set__
并且你'重新尝试删除该属性,反之亦然.(如果它没有所需的方法,它会引发异常.)如果数据描述符也有 __get__
,它也会拦截获取属性的尝试;否则,Python 将退回到正常的属性查找行为,就好像它根本不是描述符一样.
Defining either __set__
or __delete__
will set a type's tp_descr_set
slot and make instances of the type data descriptors. A data descriptor will always be invoked for attempts to set or delete the attribute it manages, even if there is an entry in the instance's dict with the same name, and even if it only has __set__
and you're trying to delete the attribute or vice versa. (If it doesn't have the needed method, it will raise an exception.) If a data descriptor also has __get__
, it will also intercept attempts to get the attribute; otherwise, Python will fall back on the normal attribute lookup behavior, as if it wasn't a descriptor at all.
这篇关于哪个是数据描述符和非数据描述符的正确定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!