functools.partial

functools.partial

functools.partial 接收一个函数,并返回一个新的函数,与装饰器不同的是functools.partial可以传递更多的参数。

def partial(func, /, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = {**keywords, **fkeywords}
        return func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

functools.partial 的目的是什么呢?答案是代码重用,是面向过程编程的代码重用。

partial


求和函数一

假设有一个需求是给对给定的任意多个整数进行求和,python 代码可以这样。

#!/usr/bin/evn python3

import functools


def fun_sum(*args):
    """实现一下简单的求和函数
    """
    return sum(args)

def main():
    print(fun_sum(1, 2, 3, 4))


if __name__ == "__main__":
    main()

运行结果如下。

python3 main.py 
10

新需求

不管求出来的和是多少,都要在这个的基础之上加上 100 再返回。

解决方案一、在调用 fun_sum 的时候多加一个 100 的参数。

#!/usr/bin/evn python3

import functools


def fun_sum(*args):
    """实现一下简单的求和函数
    """
    return sum(args)


def main():
    print(fun_sum(1, 2, 3, 4, 100))#把 100 直接加在后面


if __name__ == "__main__":
    main()

运行效果。

python3 main.py 
110

这样是可以解决问题,时间一长 100 这个常量鬼自己当初是怎么来的。


解决方案二、增加一个新的函数把这个 + 100 的功能特异化一下。

#!/usr/bin/evn python3

import functools


def fun_sum(*args):
    """实现一下简单的求和函数
    """
    return sum(args)


def fun_sum_plus_100(*args):
    """对 *args 求和,并在和的基础之上再加上 100
    """
    return sum(args) + 100


def main():
    print(fun_sum_plus_100(1, 2, 3, 4))


if __name__ == "__main__":
    main()

执行效果。

python3 main.py 
110

总结问题

如果使用第一个解决方案,遇到 + 100 的场景越多,那么 100 这个常量就重复出现的次数就越多;并且时间一长还有可能忘记了当初为什么要这么做。使用第二个方案虽然语义上更加明确,但是我们又多定义了一个函数。并且这个函数只是屏蔽一下另一个函数要多传递一个参数的场景,感觉上用了牛刀。


使用 functools.partial

下面看一下 functools.partial 如何改进代码。

#!/usr/bin/evn python3

import functools


def fun_sum(*args):
    """实现一下简单的求和函数
    """
    return sum(args)

fun_sum_plus_100 = functools.partial(fun_sum, 100)


def main():
    print(fun_sum_plus_100(1, 2, 3, 4))


if __name__ == "__main__":
    main()

运行效果。

python3 main.py 
110

总结

functools.partial 用于在那些通用的方法上加上更多的参数,以让它适更加特殊的场景。就是有点像面向对象编程中的定义子类。