15.04.2013 Views

Core Python Programming (2nd Edition)

Core Python Programming (2nd Edition)

Core Python Programming (2nd Edition)

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

A descriptor is a class attribute, so all class attributes have the highest priority. You can even replace a<br />

descriptor by simply reassigning its original reference to other objects. They are followed closely behind<br />

by descriptors with __get__() and __set__() implemented. If you have an agent, it will do all your work<br />

for you!<br />

Otherwise, it should just default to the local object's __dict__, meaning that it will be an instance<br />

attribute. The non-data descriptors come next. This may sound surprising because on first glance, one<br />

would think that these should be higher up in the food chain than instance attributes, but that is not the<br />

case. The purpose of non-data descriptors is only to provide a value if one is not already part of an<br />

instance, sort of how __getattr__() is only called if an attribute cannot be found in an instance's<br />

__dict__!<br />

Speaking of __getattr__(), if no non-data descriptor is found, then __getattribute__() raises an<br />

AttributeError, and that in turn causes __getattr__() to be invoked as the last stand before<br />

AttributeError is raised to the user.<br />

Descriptor Examples<br />

Let us start with a very boring example... a descriptor that just discards any attempt to retrieve or set a<br />

value from and to an attribute, respectively. Actually, all of the examples here just ignore all requests,<br />

but they are incremental, and we hope that you can figure out a little more about descriptors for each<br />

one:<br />

class DevNull1(object):<br />

def __get__(self, obj, typ=None):<br />

pass<br />

def __set__(self, obj, val):<br />

pass<br />

We create a class that uses this descriptor and try to assign something to it as well as display its value:<br />

>>> class C1(object):<br />

... foo = DevNull1()<br />

...<br />

>>> c1 = C1()<br />

>>> c1.foo = 'bar'<br />

>>> print 'c1.foo contains:', c1.foo<br />

c1.foo contains: None<br />

That was not too terribly exciting... how about one where the descriptor methods at least give some<br />

output to show what is going on?<br />

class DevNull2(object):<br />

def __get__(self, obj, typ=None):<br />

print 'Accessing attribute... ignoring'<br />

def __set__(self, obj, val):<br />

print 'Attempt to assign %r... ignoring' % (val)<br />

Now let us see this one in action:

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!