Both of them are python from documents :
the first one says:
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).
the second one says:
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.
The question is : is it enough to only define __set__
to make a data descriptor ?
And we I refer to the python source code, I found this :
#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
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)
The output makes me confusing again:
start
a
b
__get__
None
According to the python attribute lookup orders : the priority of data descriptor is higher than obj.__dict__
.
My example shows : Only the descriptor defines both __set__
and __get__
makes it a data descriptor !
Which one is the right answer ?
__set__
--- > data descriptor
or
__get__
and __set__
---> data descriptor ?
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 inobject.__getattribute__
to determine what counts as a data descriptor, and either__set__
or__delete__
will causetp_descr_set
to be non-null.The language reference also explains why
Set
doesn't override the instance dict fora.b
:Defining either
__set__
or__delete__
will set a type'stp_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.