在python的Currying装饰员

Elf*_*ЯUs 18 python decorator currying

我正在尝试在python中写一个currying装饰器,我想我已经有了一般的想法,但仍然有一些不正常的情况......

def curry(fun):

    cache = []
    numargs = fun.func_code.co_argcount

    def new_fun(*args, **kwargs):
        print args
        print kwargs
        cache.extend(list(args))

        if len(cache) >= numargs:   # easier to do it explicitly than with exceptions

            temp = []
            for _ in xrange(numargs):
                temp.append(cache.pop())
            fun(*temp)

    return new_fun


@curry
def myfun(a,b):
    print a,b
Run Code Online (Sandbox Code Playgroud)

虽然对于以下情况,这可以正常工作:

myfun(5)
myfun(5)
Run Code Online (Sandbox Code Playgroud)

对于以下情况,它失败:

myfun(6)(7)
Run Code Online (Sandbox Code Playgroud)

任何有关如何正确执行此操作的指示将非常感谢!

谢谢!

geo*_*org 27

以下实现是天真的,谷歌为"currying python"更准确的例子.

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

@curry
def myfun(a,b,c):
    print '%d-%d-%d' % (a,b,c)



myfun(11,22,33)
myfun(44,55)(66)
myfun(77)(88)(99)
Run Code Online (Sandbox Code Playgroud)

  • 在python 2.6或python 3中,第3行应写为:argc = x .__ code __.co_argcount (5认同)
  • “ Google for currying python”:这很有趣,因为它现在是Google的最佳搜索结果。 (2认同)

MRo*_*lin 8

对于源代码currytoolz可在下面的链接.

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

它处理args,kwargs,内置函数和错误处理.它甚至将文档字符串包裹回到咖喱对象上.

  • 这是迄今为止最好的答案,并且使用库的cytoolz版本非常快.我不认为这里的任何其他答案正确处理默认参数. (4认同)

Sha*_*ank 5

这里的许多答案都未能解决柯里化函数应该只接受一个参数这一事实。

引用维基百科

在数学和计算机科学中,柯里化是将带有多个参数(或参数元组)的函数的求值转换为求值一系列函数的技术,每个函数都有一个参数(偏应用)。

选择用递归来装饰它,而不是递归 co_argcount来装饰它,这是一个相当优雅的解决方案。

from functools import partial, wraps, reduce

def 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 _
Run Code Online (Sandbox Code Playgroud)

如上所示,编写一个装饰器也是相当简单的uncurry。:) 不幸的是,生成的非柯里化函数将允许任意数量的参数,而不是要求特定数量的参数,这对于原始函数来说可能并非如此,因此它不是 的真正逆curry。在这种情况下,真正的逆实际上类似于unwrap,但需要curry使用或类似的东西为每个新创建的函数functools.wraps设置属性:__wrapped__

def unwrap(f):
    try:
        return unwrap(f.__wrapped__)
    except AttributeError:
        return f
Run Code Online (Sandbox Code Playgroud)