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

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

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

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

David Ascher, Alex Martelli, Anna Ravenscroft

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

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

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







Recipe 20.11. Allowing Chaining of Mutating List Methods


Credit: Stephan Diehl, Alex Martelli


Problem


The methods of the
list type that mutate a list object in
placemethods such as append and
sortreturn None. To call
a series of such methods, you therefore need to use a series of
statements. You would like those methods to return
self to enable you to chain a
series of calls within a single expression.


Solution


A custom metaclass can offer an elegant approach to this task:

def makeChainable(func):
''' wrapp a method returning None into one returning self '''
def chainableWrapper(self, *args, **kwds):
func(self, *args, **kwds)
return self
# 2.4 only: chainableWrapper._ _name_ _ = func._ _name_ _
return chainableWrapper
class MetaChainable(type):
def _ _new_ _(mcl, cName, cBases, cDict):
# get the "real" base class, then wrap its mutators into the cDict
for base in cBases:
if not isinstance(base, MetaChainable):
for mutator in cDict['_ _mutators_ _']:
if mutator not in cDict:
cDict[mutator] = makeChainable(getattr(base, mutator))
break
# delegate the rest to built-in 'type'
return super(MetaChainable, mcl)._ _new_ _(mcl, cName, cBases, cDict)
class Chainable: _ _metaclass_ _ = MetaChainable
if _ _name_ _ == '_ _main_ _':
# example usage
class chainablelist(Chainable, list):
_ _mutators_ _ = 'sort reverse append extend insert'.split( )
print ''.join(chainablelist('hello').extend('ciao').sort( ).reverse( ))
# emits: oolliheca


Discussion


Mutator methods of mutable objects such as lists and dictionaries
work in place, mutating the object they're called
on, and return None. One reason for this behavior
is to avoid confusing programmers who might otherwise think such
methods build and return new objects. Returning
None also prevents you from
chaining a sequence of mutator calls, which some
Python gurus consider bad style because it can lead to very dense
code that may be hard to read.

Some programmers, however, occasionally prefer the chained-calls,
dense-code style. This style is particularly useful in such contexts
as lambda forms and list comprehensions. In these contexts, the
ability to perform actions within an expression, rather than in
statements, can be crucial. This recipe shows one way you can tweak
mutators' return values to allow chaining. Using a
custom metaclass means the runtime overhead of introspection is paid
only rarely, at class-creation time, rather than repeatedly. If
runtime overhead is not a problem for your application, it may be
simpler for you to use a delegating wrapper idiom that was posted to
comp.lang.python by Jacek Generowicz:

class chainable(object):
def _ _init_ _(self, obj):
self.obj = obj
def _ _iter_ _(self):
return iter(self.obj)
def _ _getattr_ _(self, name):
def proxy(*args, **kwds):
result = getattr(self.obj, name)(*args, **kwds)
if result is None: return self
else: return result
# 2.4 only: proxy._ _name_ _ = name
return proxy

The use of this wrapper is quite similar to that of classes obtained
by the custom metaclass presented in this recipe's
Solutionfor example:

print ''.join(chainable(list('hello')).extend('ciao').sort( ).reverse( ))
# emits: oolliheca


See Also


Library Reference and Python in a
Nutshell
docs on built-in type list
and special methods _ _new_ _ and _
_getattr_ _
.


/ 394