Currying decorator in python Currying decorator in python python python

Currying decorator in python


The below implementation is naive, google for "currying python" for more accurate examples.

def curry(x, argc=None):    if argc is None:        argc = x.func_code.co_argcount    def p(*a):        if len(a) == argc:            return x(*a)        def q(*b):            return x(*(a + b))        return curry(q, argc - len(a))    return p@currydef myfun(a,b,c):    print '%d-%d-%d' % (a,b,c)myfun(11,22,33)myfun(44,55)(66)myfun(77)(88)(99)


The source code for curry in the toolz library is available at the following link.

https://github.com/pytoolz/toolz/blob/master/toolz/functoolz.py

It handles args, kwargs, builtin functions, and error handling. It even wraps the docstrings back onto the curried object.


Many of the answers here fail to address the fact that a curried function should only take one argument.

A quote from Wikipedia:

In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument (partial application).

Choosing to decorate it with recursion and without co_argcount makes for a decently elegant solution.

from functools import partial, wraps, reducedef curry(f):    @wraps(f)    def _(arg):        try:            return f(arg)        except TypeError:            return curry(wraps(f)(partial(f, arg)))    return _def uncurry(f):    @wraps(f)    def _(*args):        return reduce(lambda x, y: x(y), args, f)    return _

As shown above, it is also fairly trivial to write an uncurry decorator. :) Unfortunately, the resulting uncurried function will allow any number of arguments instead of requiring a specific number of arguments, as may not be true of the original function, so it is not a true inverse of curry. The true inverse in this case would actually be something like unwrap, but it would require curry to use functools.wraps or something similar that sets a __wrapped__ attribute for each newly created function:

def unwrap(f):    try:        return unwrap(f.__wrapped__)    except AttributeError:        return f