Introduction


Credit: Raymond Hettinger

I had my power drill slung low on my toolbelt and I said, "Go ahead, honey.Break something."

Tim Allen

on the challenges of figuring out whatto do with a new set of general-purpose tools

This chapter is last because it deals with issues that look or sound difficult, although they really aren't. It is about Python's power tools.

Though easy to use, the power tools can be considered advanced for several reasons. First, the need for them rarely arises in simple programs. Second, most involve introspection, wrapping, and forwarding techniques available only in a dynamic language like Python. Third, the tools seem advanced because when you learn them, you also develop a deep understanding of how Python works internally.

Last, as with the power tools in your garage, it is easy to get carried away and create a gory mess. Accordingly, to ward off small children, the tools were given scary names such as descriptors, decorators, and metaclasses (such names as pangalaticgarglebaster were considered a bit too long).

Because these tools are so general purpose, it can be a challenge to figure out what to do with them. Rather that resorting to Tim Allen's tactics, study the recipes in this chapter: they will give you all the practice you need. And, as Tim Peters once pointed out, it can be difficult to devise new uses from scratch, but when a real problem demands a power tool, you'll know it when you need it.

Descriptors

The concept of descriptors is easy enough. Whenever an attribute is looked up, an action takes place. By default, the action is a get, set, or delete. However, someday you'll be working on an application with some subtle need and wish that more complex actions could be programmed. Perhaps you would like to create a log entry every time a certain attribute is accessed. Perhaps you would like to redirect a method lookup to another method. The solution is to write a function with the needed action and then specify that it be run whenever the attribute is accessed. An object with such functions is called a descriptor (just to make it sound harder than it really is).

While the concept of a descriptor is straightforward, there seems to be no limit to what can be done with them. Descriptors underlie Python's implementation of methods, bound methods, super, property, classmethod, and staticmethod. Learning about the various applications of descriptors is key to mastering the language.

The recipes in this chapter show how to put descriptors straight to work. However, if you want the full details behind the descriptor protocol or want to know exactly how descriptors are used to implement super, property, and the like, see my paper on the subject at http://users.rcn.com/python/download/Descriptor.htm.

Decorators

Decorators are even simpler than descriptors. Writing myfunc=wrapper(myfunc) was the common way to modify or log something about another function, which took place somewhere after myfunc was defined. Starting with Python 2.4, we now write @wrapper just before the def statement that performs the definition of myfunc. Common examples include @staticmethod and @classmethod. Unlike Java declarations, these wrappers are higher-order functions that can modify the original function or take some other action. Their uses are limitless. Some ideas that have been advanced include @make_constants for bytecode optimization, @atexit to register a function to be run before Python exits, @synchronized to automatically add mutual exclusion locking to a function or method, and @log to create a log entry every time a function is called. Such wrapper functions are called decorators (not an especially intimidating name but cryptic enough to ward off evil spirits).

Metaclasses

The concept of a metaclass sounds strange only because it is so familiar. Whenever you write a class definition, a mechanism uses the name, bases, and class dictionary to create a class object. For old-style classes that mechanism is types.ClassType. For new-style classes, the mechanism is just type. The former implements the familiar actions of a classic class, including attribute lookup and showing the name of the class when repr is called. The latter adds a few bells and whistles including support for _ _slots_ _ and _ _getattribute_ _. If only that mechanism were programmable, what you could do in Python would be limitless. Well, the mechanism is programmable, and, of course, it has an intimidating name, metaclasses.

The recipes in this chapter show that writing metaclasses can be straightforward. Most metaclasses subclass type and simply extend or override the desired behavior. Some are as simple as altering the class dictionary and then forwarding the arguments to type to finish the job.

For instance, say that you would like to automatically generate getter methods for all the private variables listed in slots. Just define a metaclass M that looks up _ _slots_ _ in the mapping, scans for variable names starting with an underscore, creates an accessor method for each, and adds the new methods to the class dictionary:

class M(type):     def _ _new_ _(cls, name, bases, classdict):         for attr in classdict.get('_ _slots_ _', ( )):             if attr.startswith('_'):                 def getter(self, attr=attr):                      return getattr(self, attr)                 # 2.4 only: getter._ _name_ _ = 'get' + attr[1:]                 classdict['get' + attr[1:]] = getter         return type._ _new_ _(cls, name, bases, classdict)

Apply the new metaclass to every class where you want automatically created accessor functions:

class Point(object):     _ _metaclass_ _ = M     _ _slots_ _ = ['_x', '_y']

If you now print dir(Point), you will see the two accessor methods as if you had written them out the long way:

class Point(object):     _ _slots_ _ = ['_x', '_y']     def getx(self):         return self._x     def gety(self):         return self._y

In both cases, among the output of the print statement, you will see the names 'getx' and 'gety'.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net