Recipe16.4.Associating Parameters with a Function (Currying)


Recipe 16.4. Associating Parameters with a Function (Currying)

Credit: Scott David Daniels, Nick Perkins, Alex Martelli, Ben Wolfson, Alex Naanou, David Abrahams, Tracy Ruggles

Problem

You need to wrap a function (or other callable) to get another callable with fewer formal arguments, keeping given values fixed for the other arguments (i.e., you need to curry a callable to make another).

Solution

Curry is not just a delightful spice used in Asian cuisineit's also an important programming technique in Python and other languages:

def curry(f, *a, **kw):     def curried(*more_a, **more_kw):         return f(*(a+more_a), dict(kw, **more_kw))     return curried

Discussion

Popular in functional programming, currying is a way to bind some of a function's arguments and wait for the rest of them to show up later. Currying is named in honor of Haskell Curry, a mathematician who laid some of the cornerstones in the theory of formal systems and processes. Some pedants (and it must be grudgingly admitted they have a point) claim that the technique shown in this recipe should be called partial application, and that "currying" is something else. But whether they're right or wrong, in a book whose title claims it's a cookbook, the use of curry in a title was simply irresistible. Besides, the use of the verb to curry that this recipe supports is the most popular one among programmers.

The curry function defined in this recipe is invoked with a callable and some or all of the arguments to the callable. (Some people like to refer to functions that accept function objects as arguments, and return new function objects as results, as higher-order functions.) The curry function returns a closure curried that takes subsequent parameters as arguments and calls the original with all of those parameters. For example:

double = curry(operator.mul, 2) triple = curry(operator.mul, 3)

To implement currying, the choice is among closures, classes with callable instances, and lambda forms. Closures are simplest and fastest, so that's what we use in this recipe.

A typical use of curry is to construct callback functions for GUI operations. When the operation does not merit a new function name, curry can be useful in creating these little functions. For example, this can be the case with commands for Tkinter buttons:

self.button = Button(frame, text='A', command=curry(transcript.append, 'A'))

Recipe 11.2 shows a specialized subset of "curry" functionality intended to produce callables that require no arguments, which are often needed for such GUI-callback usage. However, this recipe's curry function is vastly more flexible, without any substantial extra cost in either complexity or performance.

Currying can also be used interactively to make versions of your functions with debugging-appropriate defaults, or initial parameters filled in for your current case. For example, database debugging work might begin by setting:

Connect = curry(ODBC.Connect, dsn='MyDataSet')

Another example of the use of curry in debugging is to wrap methods:

def report(originalFunction, name, *args, **kw):     print "%s(%s)"%(name, ', '.join(map(repr, args) +                                    [k+'='+repr(kw[k]) for k in kw])     result = originalFunction(*args, **kw)     if result: print name, '==>', result     return result class Sink(object):     def write(self, text): pass dest = Sink( ) dest.write = curry(report, dest.write, 'write') print >>dest, 'this', 'is', 1, 'test'

If you are creating a function for regular use, the def fun form of function definition is more readable and more easily extended. As you can see from the implementation, no magic happens to specialize the function with the provided parameters. curry should be used when you feel the code is clearer with its use than without. Typically, this use will emphasize that you are only providing some pre-fixed parameters to a commonly used function, not providing any separate processing.

Currying also works well in creating a "lightweight subclass". You can curry the constructor of a class to give the illusion of a subclass:

BlueWindow = curry(Window, background="blue")

BlueWindow._ _class_ _ is still Window, not a subclass, but if you're changing only default parameters, not behavior, currying is arguably more appropriate than subclassing anyway. And you can still pass additional parameters to the curried constructor.

Two decisions must be made when coding a curry implementation, since both positional and keyword arguments can come in two "waves"some at currying time, some more at call time. The two decisions are: do the call-time positional arguments go before or after the currying-time ones? do the call-time keyword arguments override currying-time ones, or vice versa? If you study this recipe's Solution, you can see I've made these decisions in a specific way (the one that is most generally useful): call-time positional arguments after currying-time ones, call-time keyword arguments overriding currying-time ones. In some circles, this is referred to as left-left partial application. It's trivial to code other variations, such as right-left partial application:

def rcurry(f, *a, **kw):     def curried(*more_a, **more_kw):         return f(*(more_a+a), dict(kw, **more_kw))     return curried

As you can see, despite the grandiose-sounding terms, this is just a matter of concatenating more_a+a rather than the reverse; and similarly, for keyword arguments, you just need to call dict(more_kw, **kw) if you want currying-time keyword arguments to override call-time ones rather than vice versa.

If you wish, you could have the curried function carry a copy of the original function's docstring, or even (easy in Python 2.4, but feasible, with a call to new.function, even in 2.3see the sidebar in Recipe 20.1) a name that is somehow derived from the original function. However, I have chosen not to do so because the original name, and argument descriptions in the docstring, are probably not appropriate for the curried version. The task of constructing and documenting the actual signature of the curried version is also feasible (with a liberal application of the helper functions from standard library module inspect), but it's so disproportionate an effort, compared to curry's delightfully simple four lines of code (!), that I resolutely refuse to undertake it.

A special case, which may be worth keeping in mind, is when the callable you want to curry is a Python function (not a bound method, a C-coded function, a callable class instance, etc.), and all you need to curry is the first parameter. In this case, the function object's _ _get_ _ special method may be all you need. It takes an arbitrary argument and returns a bound-method object with the first parameter bound to that argument. For example:

>>> def f(adj, noun='world'): ...     return 'Goodbye, %s %s!' % (adj, noun) ...  >>> cf = f._ _get_ _('cruel') >>> print cf( ) Goodbye, cruel world! >>> cf <bound method ?.f of 'cruel'> >>> type(cf) <type 'instancemethod'> >>> cf.im_func <function f at 0x402dba04> >>> cf.im_self 'cruel'

See Also

Recipe 11.2 shows a specialized subset of the curry functionality that is specifically intended for GUI callbacks; docs for the inspect module and the dict built-in type in the Library Reference and Python in a Nutshell.



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