我什么时候应该使用函数柯里化?
我什么时候应该使用柯里化函数? 这和我之前的想法不太一致,我需要纠正一下自己。
作为我学习的一部分,这个链接让我对函数柯里化有了一些理解。下面是一个例子:
def curry2(f):
"""Returns a function g such that g(x)(y) == f(x, y)
>>> from operator import add
>>> add_three = curry2(add)(3)
>>> add_three(4)
"""
def g(x):
def h(y):
return f(x, y)
return h
return g
在任何应用程序中,如果我知道参数的数量是固定的(比如说2个参数),而函数的名字是 normalise_range
(假设),那么我会定义一个函数 def normalise_range(x, y):
,并直接通过调用 normalise_range(x, y)
在我的应用中使用它。
在任何应用程序中,如果我知道参数的数量是固定的(比如说2个参数),但函数的名字是变化的(可能是 normalise_range
、average
,或者我不知道..),那么我会使用 def curry2(f):
,就像上面那样,这个函数可以接受所有需要两个参数的函数(固定的)。
我的问题是:
- 我的理解正确吗?
- 如果正确的话,我们能不能考虑对参数数量可变的函数进行柯里化?
3 个回答
从很多方面来看,把柯里化和部分参数应用结合起来,类似于我们在面向对象编程中所说的“工厂模式”。柯里化让程序员可以创建一些专门化的函数,正如其他人在这个论坛中提到的那样。比如,看看下面这个快速排序的实现,它虽然不够高效,但很优雅:
leq = lambda x: lambda y: x <= y
gth = lambda x: lambda y: x > y
def qsort(L):
if L:
smalls = filter(gth(L[0]), L[1:])
bigs = filter(leq(L[0]), L[1:])
return qsort(smalls) + [L[0]] + qsort(bigs)
else:
return L
print(qsort([2, 4, 1, 4, 2]))
柯里化有至少两个我能想到的好处:
1) 它可以让你的代码保持简洁,也能让你的思维更清晰,避免重复。
比如说,你有一个这样的函数:
def call_me(context, args):
...
通过柯里化,你可以得到一个针对特定上下文的专用函数,这样你就可以随意使用它,而不需要再重复写这个上下文。
2) 用一个输入的函数来思考,比起处理多个参数要简单得多;不过这有时候也可以争论。
另请参见:柯里化和部分应用有什么区别?
函数柯里化的目的是为了从更通用的函数中轻松得到专门化的函数。 你可以通过在不同的时间预先设置一些参数,并在之后保持这些参数不变来实现这一点。
这和命名没有关系。在Python中,你可以随时轻松地重命名变量或函数。
举个例子:
def simple_function(a):
def line(b=0):
def compute(x):
return [a+b * xi for xi in x]
return compute
return line
x = range(-4, 4, 1)
print('x {}'.format(list(x)))
print('constant {}'.format(simple_function(3)()(x)))
print('line {}'.format(simple_function(3)(-2)(x)))
结果是
x [-4, -3, -2, -1, 0, 1, 2, 3]
constant [3, 3, 3, 3, 3, 3, 3, 3]
line [11, 9, 7, 5, 3, 1, -1, -3]
现在这看起来并没有那么令人兴奋。它只是把类型为 f(a,b,c)
的函数调用替换成了类型为 f(a)(b)(c)
的调用,这在Python中甚至可能被认为是比较不优雅的写法。
但它让你可以这样做:
line_through_zero = simple_function(0)
print('line through zero {}'.format(line_through_zero(1)(x))) # only slope and x
结果是
line through zero [-4, -3, -2, -1, 0, 1, 2, 3]
所以,柯里化的好处在于你可以得到一些固定参数的专门化函数,这样就可以用这些函数代替每次都写更一般形式并设置参数的麻烦。
柯里化的替代方法有: partial
、lambda
和 默认参数
。所以在实际使用中,柯里化可能会有用,但如果你想,也可以找到其他方法来解决问题。
更多内容请见 Python中的柯里化