偏函数(partial)把函数部分的参数固定下来,相当于为部分参数添加了一个固定的默认值,并返回一个新的可调用对象。
使用partial生成的新函数,是对原函数的封装。
基于一个函数创建一个新的可调用对象,把原函数的某些参数固定。
使用这个函数可以把接受一个或多个参数的函数改变成需要回调的API,这样参数更少。
按照官方说法,偏函数的实现原理大致等价于以下代码:
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
固定关键字参数y
from functools import partial
def add(x, y):
return x + y
# 这里返回一个partial对象
newadd = partial(add, y=5)
print(newadd)
# functools.partial(<function add at 0x1005a21e0>, y=5)
# 除去魔术方法,一个partial对象包含三个属性
# - func,指向partial函数传递的函数对象
# - args,收集partial函数传递的位置参数
# - keywords,收集partial函数传递的关键字参数
print(newadd(7))
# 12
print(newadd(7, y=6))
# 13
print(newadd(y=10, x=4))
# 14
# print(newadd(4, 5)) # 这里由于y已经固定为关键字参数y=5,只能通过关键字传参覆盖,实际上这里的y是keyword-only参数,通过函数签名可以看到
固定位置参数x
newadd = partial(add, 4)
print(newadd(5))
# 9
# print(newadd(x=1, y=2)) # 不能这样传参,这里由于x已经固定为位置参数4,不能通过关键字参数覆盖
同时固定位置参数x和y
# 为了能打印出多出来的位置参数,这里手动传一个*args,不过被partial处理后这里只能收集到被固定x,y之外的参数
def add(x, y, *args):
print(args)
return x + y
# 实际上,不显式传递可变参数,partial也会处理所有传递进来的参数,官方说法如下:
# If more arguments are supplied to the call, they are appended to args.
# If additional keyword arguments are supplied, they extend and override keywords.
# 多出来的位置参数会被追加到partial的args属性中
# 多出来的关键字参数会更新到partial的keywords属性中
newadd = partial(add, 1, 3, 6, 5)
print(newadd(7))
# (6, 5, 7)
# 4
print(newadd(7,10))
# (6, 5, 7, 10)
# 4
print(newadd())
# (6, 5)
# 4
# print(newadd(9, 10, y=20, x=26)) # 这里同样会抛出异常,原因不再赘述
参考:
https://docs.python.org/3/library/functools.html#functools.partial