Any object with a __get__() method, and optionally
__set__() and __delete__()
methods, accepting specific parameters is said to follow the
descriptor protocol. Such an object qualifies as
a descriptor and can be placed inside a type's
__dict__ to do something special when an attribute
is retrieved, set or deleted. An empty descriptor is shown below.
Example 1.3. A simple descriptor
class Desc(object):
"A descriptor example that just demonstrates the protocol"
def __get__(self, obj, typ=None):
pass
def __set__(self, obj, val):
pass
def __delete__(self, obj):
pass
What we defined above is a class that can be instantiated to create a descriptor. Let's see how we can create a descriptor, attach it to a type and put it to work.
Example 1.4. Using a descriptor
class C(object):
"A class with a single descriptor"
d = Desc()
cobj = C()
x = cobj.d
cobj.d = "setting a value"
cobj.__dict__['d'] = "try to force a value"
x = cobj.d
del cobj.d
x = C.d
C.d = "setting a value on class"
Note that when accessed from the type itself, only the
__get__() method comes in the picture, setting or
deleting the attribute will actually replace or remove the
descriptor.
Descriptors work only when attached to type objects. Sticking a descriptor in a non-type object gives us nothing.