柯里化(currying)是指通过“部分参数应用”(partial argument application)从现有函数派生出新函数的技术。
假设有一个执行两数相加的简单函数:
def add_numbers(x , y):
return x+y
通过这个函数,如果已知第一个参数x的值为5,则可以派生出参数被缩减只剩一个(只有第二个参数y)的新函数
add_5 = lambda y : add_numbers(5 , y)
add_numbers的第二个参数称为“柯里化的”(curried),定义一个可以调用现有函数的新函数,python内置的funtools模块可以用partial函数将此过程简化
from functools import partial
add_5 = partial(add_numbers , 5)
python中partial的使用规则
概念
函数声明如下:
functools.partial(func [, *args] [, **keywords])
返回一个可以像函数一样被调用的partial实例,在调用时使用args和keywords参数。使用python实现时,类似于:
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
通常的使用方法(位置参数)
通常的用法是在原函数声明的参数中,从前往后(从左往右)连续将参数值固定:
>>> from functools import partial
>>> def add_numbers(x, y, z):
... return x+y+z
...
#已知第一个参数x的值为5和第二个参数y的值为6
>>> add_5_6 = partial(add_numbers,5,6)
>>> test1(7)
18
#已知第一个参数x的值为5,第二个参数y的值为6,第三个参数z的值为7
>>> add_5_6_7 = partial(add_numbers,5,6,7)
>>> add_5_6_7(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add_numbers() takes exactly 3 arguments (4 given)
通常用法是使用位置参数,按照从前往后(从左往右)顺序把位置参数依次固定,假如需求是要使后面的参数固定,则可以使用关键字参数固定指定的参数
新的使用方法(关键字参数)
#已知第三个参数z的值为7
>>> add_7 = partial(add_numbers, z=7)
>>> add_7(5,6)
18
#已知第一个参数x的值为5盒第三个参数z的值为7
>>> add_5_7 = partial(add_numbers, x=5 , z=7)
>>> add_5_7(6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add_numbers() got multiple values for argument 'x'
位置参数默认会从前往后(从左往右)顺序匹配,位置参数只按该顺序从头匹配到尾,位置参数傻瓜的认为所有参数无论其中参数是否已经被关键字参数匹配过都被视为未匹配的,当某些参数已经被关键字参数匹配过,但柯里化的参数再使用位置参数时依然会按照从前往后(从左往右)顺序匹配,就会造成同一变量赋多值的错误,解决办法就是柯里化的参数只有同样使用关键字参数来指定固定
#已知第一个参数x的值为5盒第三个参数z的值为7
>>> add_5_7 = partial(add_numbers, x=5 , z=7)
>>> add_5_7(y=6)
18
总结
使用partial规则
1、起始连续的参数是被位置参数固定,柯里化的参数可以使用位置参数或关键字参数。起始连续参数被关键字参数固定,柯里化的参数只能使用关键字参数
#已知第一个参数x的值为5,使用位置参数固定
>>> add_5 = partial(add_numbers,5)
>>> add_5(6,7)
18
>>> add_5(y=6,z=7)
18
#已知第一个参数x的值为5,使用关键字参数固定
>>> add_5 = partial(add_numbers, x=5)
>>> add_5(y=6,z=7)
18
2、结尾连续的参数是被关键字参数固定,柯里化的参数可以使用位置参数或关键字参数
#已知第三个参数z的值为7,使用关键字参数固定
>>> add_7 = partial(add_numbers,z=7)
>>> add_7(5,6)
18
>>> add_7(x=5,y=6)
18
3、不连续的参数是被关键字参数固定,柯里化的参数如果只在起始连续则可以使用位置参数或关键字参数,但柯里化的参数如果在除起始连续外的其他位置则只能使用关键字参数
#已知第二个参数y的值为6,使用关键字参数固定
>>> add_6 = partial(add_numbers,y=6)
>>> add_6(5,z=7)
18
>>> add_6(x=5,z=7)
18