我正在尝试在python 2.6运行时从http://www.ibm.com/developerworks/linux/library/l-prog3.html运行此代码段。
from functional import *
taxcalc = lambda income,rate,deduct: (income-(deduct))*rate
taxCurry = curry(taxcalc)
taxCurry = taxCurry(50000)
taxCurry = taxCurry(0.30)
taxCurry = taxCurry(10000)
print "Curried taxes due =",taxCurry
print "Curried expression taxes due =", \
curry(taxcalc)(50000)(0.30)(10000)
好的,所以我从http://www.python.org/dev/peps/pep-0309/了解到,功能被重命名为functools而curry为partial,但只是进行重命名并没有帮助。我收到错误:
taxCurry = taxCurry(50000)
TypeError: <lambda>() takes exactly 3 arguments (1 given)
以下确实有效,但我真的需要改变它吗?
from functools import partial
taxcalc = lambda income,rate,deduct: (income-(deduct))*rate
taxCurry = partial(taxcalc)
taxCurry = partial(taxCurry, 50000)
taxCurry = partial(taxCurry, 0.30)
taxCurry = partial(taxCurry, 10000)
print "Curried taxes due =", taxCurry()
print "Curried expression taxes due =", \
taxcalc(50000, 0.30, 10000)
有没有更好的方法来保留原始示例的机制?最后原始的例子是真正的currying还是只是部分应用? (根据http://www.uncarved.com/blog/not_currying.mrk)
感谢您的时间
答案 0 :(得分:2)
我猜他们改变它的原因是因为Python是动态类型的。这意味着如果出现任何问题,调试原始curry
代码将非常困难 - 比像Haskell这样的语言更难以直接获得一个好的类型错误。所以我认为用更明确的partial
版本替换它是一个合理的决定(对我来说看起来更加pythonic)。
您的示例也有点奇怪,因为您只是将部分应用的函数重新分配给相同的名称。通常,部分应用的函数将被赋予另一个函数。至少这是我能想到的Python中唯一合理的用例。
答案 1 :(得分:1)
toolz
project中curry
的实施应该是替代品。
$ pip install toolz
>>> from toolz import curry
答案 2 :(得分:1)
我写了an implementation of a curry decorator,效果很好:
def curry(func):
"""
Decorator to curry a function, typical usage:
>>> @curry
... def foo(a, b, c):
... return a + b + c
The function still work normally:
>>> foo(1, 2, 3)
6
And in various curried forms:
>>> foo(1)(2, 3)
6
>>> foo(1)(2)(3)
6
This also work with named arguments:
>>> foo(a=1)(b=2)(c=3)
6
>>> foo(b=1)(c=2)(a=3)
6
>>> foo(a=1, b=2)(c=3)
6
>>> foo(a=1)(b=2, c=3)
6
And you may also change your mind on named arguments,
But I don't know why you may want to do that:
>>> foo(a=1, b=0)(b=2, c=3)
6
Finally, if you give more parameters than expected, the exception
is the expected one, not some garbage produced by the currying
mechanism:
>>> foo(1, 2)(3, 4)
Traceback (most recent call last):
...
TypeError: foo() takes exactly 3 arguments (4 given)
"""
def curried(*args, **kwargs):
if len(args) + len(kwargs) >= func.__code__.co_argcount:
return func(*args, **kwargs)
return (lambda *args2, **kwargs2:
curried(*(args + args2), **dict(kwargs, **kwargs2)))
return curried
if __name__ == "__main__":
import doctest
doctest.testmod()