偏函数

偏函数(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

posted @ 2018-09-02 21:16  KeithTt  阅读(239)  评论(0编辑  收藏  举报