I read somewhere about the fact you can have a descriptor with __set__
and without __get__
.
How does it work?
Does it count as a data descriptor? Is it a non-data descriptor?
Here is a code example:
class Desc:
def __init__(self, name):
self.name = name
def __set__(self, inst, value):
inst.__dict__[self.name] = value
print("set", self.name)
class Test:
attr = Desc("attr")
>>>myinst = Test()
>>> myinst.attr = 1234
set attr
>>> myinst.attr
1234
>>> myinst.attr = 5678
set attr
>>> myinst.attr
5678
Python __get__ Magic Method. Python's __get__() magic method defines the dynamic return value when accessing a specific instance and class attribute. It is defined in the attribute's class and not in the class holding the attribute (= the owner class).
Creating descriptors using property typeWith the property(), it is easy to create a usable descriptor for any attribute. The syntax for creating property() is property(fget=None, fset=None, fdel=None, doc=None) where: fget – attribute get method. fset – attribute set method.
Invoking descriptor : Descriptors are invoked automatically whenever it receives the call for a set() method or get() method. For example, obj. gfg looks up gfg in the dictionary of obj . If gfg defines the method __get__() , then gfg.
The Cliff's Notes version: descriptors are a low-level mechanism that lets you hook into an object's attributes being accessed. Properties are a high-level application of this; that is, properties are implemented using descriptors.
The descriptor you've given in the example is a data descriptor.
Upon setting the attribute, as any other data descriptor, it takes the highest priority and is called like so:
type(myinst).__dict__["attr"].__set__(myinst, 1234)
This in turn, adds attr
to the instance dictionary according to your __set__
method.
Upon attribute access, the descriptor is checked for having the __get__
method but fails, causing for the search to be redirected to the instance's dictionary like so:
myinst.__dict__["attr"]
If it is not found in the instance dictionary, the descriptor itself is returned.
This behavior is shortly documented in the data model like so:
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.
Common usecases include avoiding {instance: value}
dictionaries inside the descriptors, and caching values in an efficient way.
In Python 3.6, __set_name__
was added to the descriptor protocol thus eliminating the need for specifying the name inside the descriptor. This way, your descriptor can be written like so:
class Desc:
def __set_name__(self, owner, name):
self.name = name
def __set__(self, inst, value):
inst.__dict__[self.name] = value
print("set", self.name)
class Test:
attr = Desc()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With