[Python-Dev] PEP 309

Dima Dorfman d+pydev at trit.org
Sun Feb 27 06:17:29 CET 2005

Nick Coghlan <ncoghlan at iinet.net.au> wrote:
> Raymond Hettinger wrote:
> >* The instance method limitation never came up for me.  However, it
> >bites to have a tool working in a way that doesn't match your mental
> >model.  We have to document the limitations, keep them in mind while
> >programming, and hope to remember them as possible causes if bugs ever
> >arise.  It would be great if these limitations could get ironed out.
> The 'best' idea I've come up with so far is to make partial a class factory 
> instead of a straight class, taking an argument that states how many 
> positional arguments to prepend at call time. A negative value would result 
> in the addition of (len(callargs)+1) to the position at call time.

Other dynamic languages, like Lisp, are in the same boat in this
respect--real currying (and things that look like it) doesn't work too well
because the API wasn't designed with it in mind (curried languages have
functions that take less-frequently-changing parameters first, but most
other languages take them last). Scheme has a nice solution for this in
SRFI 26 (http://srfi.schemers.org/srfi-26/). It looks like this:

    (cut vector-set! x <> 0)

That produces a function that takes one argument. The <> is an
argument slot; for every <> in the cut form, the resultant callable
takes another argument. (This explanation is incomplete, and there are
some other features; read the SRFI for details.) I've been using
something similar in Python for a while, and I really like it. It
doesn't look as good because the slot has to be a real object and not
punctuation, but it works just as well. For example:

    cut(islice, cutslot, 0, 2)

That's pretty readable to me. My version also allows the resultant
callable to take any number of parameters after the slots have been
satisfied, so partial is just the special case of no explicit slots.
Perhaps a full example will make it clearer:

    >>> def test(a, b, c):
    ...     print 'a', a, 'b', b, 'c', c
    >>> f = cut(test, cutslot, 'bravo')
    >>> f('alpha', 'charlie')
    a alpha b bravo c charlie

Here, b is specialized at cut time, a is passed through the slot, and
c is passed through the implicit slots at the end. The only thing this
can't do is a generic right-"curry"--where we don't know how many
parameters come before the one we want to specialize. If someone wants
to do that, they're probably better off using keyword arguments.

So far, my most common use for this is to specialize the first
argument to map, zip, or reduce. Very few cases actually need an
explicit cutslot, but those that do (like the islice example above)
look pretty good with it. My reasons for using cut instead of lambda
are usually cosmetic--the cut form is shorter and reads better when
what I'm doing would be a curry in a language designed for that. Throw
in a compose function and I almost never need to use lambda in a
decorator <ducks and runs from the anti-lambda crowd>.

More information about the Python-Dev mailing list