Examples of descriptors?
Michele Simionato
mis6 at pitt.edu
Sat May 31 15:49:34 EDT 2003
"Edward C. Jones" <edcjones at erols.com> wrote in message news:<bba9u0$li0$1 at bob.news.rcn.net>...
> What, exactly, is a "descriptor"? The closest thing to a definition that
> I can find is: a class that defines __get__, __set__, and __delete__.
> Where can I find some examples?
>
> Ed Jones
It is enough for a class to define __get__ to be a descriptor class.
Here is an example:
::
#<simpledescr.py>
class ChattyAttr(object):
"""Chatty descriptor class; descriptor objects are intended to be
used as attributes in other classes"""
def __get__(self, obj, cls=None):
binding=obj is not None
if binding:
return 'You are binding %s to %s' % (self,obj)
else:
return 'Calling %s from %s' % (self,cls)
class C(object):
d=ChattyAttr()
c=C()
print c.d # <=> type(c).__dict__['d'].__get__(c,type(c))
print C.d # <=> C.__dict__['d'].__get__(None,C)
#</simpledescr.py>
with output:
::
You are binding <ChattyAttr object at 0x401bc1cc> to
<C object at 0x401bc2ec>
Calling <ChattyAttr object at 0x401bc1cc> from <class 'C'>
Notice that invoking a method with the syntax ``C.d`` or ``c.d``
involves calling ``__get__``. The ``__get__`` signature is fixed: it is
`` __get__=__get__(self,obj,cls=None)``; the notation
``self.descr_attr`` automatically passes ``self`` and ``self.__class__`` to
``__get__``.
Custom descriptors can be used to restrict the access to objects in a
more general way than trough properties. For instance, suppose one
wants to raise an error if a given attribute 'a' is accessed, both
from the class and from the instance: a property cannot help here,
since it works only from the instance. The solution is the following
custom descriptor:
::
#<oopp.py>
class AccessError(object):
"""Descriptor raising an AttributeError when the attribute is
accessed""" #could be done with a property
def __init__(self,errormessage):
self.msg=errormessage
def __get__(self,obj,cls=None):
raise AttributeError(self.msg)
#</oopp.py>
>>> from oopp import AccessError
>>> class C(object):
... a=AccessError("'a' cannot be accessed")
>>> c=C()
>>> c.a #error
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "oopp.py", line 313, in __get__
raise AttributeError(self.msg)
AttributeError: 'a' cannot be accessed
>>> C.a #error
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "oopp.py", line 313, in __get__
raise AttributeError(self.msg)
AttributeError: 'a' cannot be accessed
Descriptors are quite sophisticated and very little documented,
but pretty powerful and essential in order to understand how Python
works under the hood. Notice that good old functions have a __get__ method
and therefore are descriptors too; descriptors are the mechanism that allows
the magic conversion of functions in methods in Python classes.
If you are confused, feel free to ask for further clarifications.
Cheers,
Michele
More information about the Python-list
mailing list