Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] - نسخه متنی

David Ascher, Alex Martelli, Anna Ravenscroft

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید






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.


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'.


/ 394