写点什么

4. Python 函数式编程之 functools 模块初体验

发布于: 刚刚

本篇博客为你说明 functools 模块中用于创建,修改函数的高阶函数。

partial 函数

partial 为偏函数(有的地方也叫做部分应用函数),它是对函数的二次封装,将现有函数的部分参数提前绑定为指定值,然后再进行计算。


由于偏函数的可变参数少,因此函数调用的难度低。


直接展示代码:


from functools import partial

# 原函数声明def show(name, level): print("name:", name, "level:", level)

# 定义偏函数,封装 show() 函数,并为 name 参数设置了默认参数show_level = partial(show, name='橡皮擦')# 由于 name 参数已经有默认值,调用偏函数时,name 可以不指定show_level(level="9级")
复制代码


上述代码就是使用 partial 函数,将一个函数的某些参数(案例中是 name)进行了固定(相当于提供了默认值),然后再返回一个新的函数,新函数参数也进行了减少。


还有一点是上述代码在调用 show_level 函数时,必须使用关键字参数形式给 level 进行传值,否则会出现 TypeError 错误,如下所示:


# 代码写成下述内容show_level("9级")# 异常如下TypeError: show() got multiple values for argument 'name'
复制代码


偏函数也可以通过匿名函数实现,例如下述代码:


# 原函数声明def show(name, level):    print("name:", name, "level:", level)

show_level = lambda y: show("橡皮擦", y)
show_level("9级")
复制代码


使用 timeit 运行 10 万次,测试一下二者的时间基本没有太大差异,所以可以互通使用,不过匿名函数还是实现一些相对简单的函数。

装饰器 @lru_cache

给函数添加 @lru_cache 装饰器,可以加快函数的运行,lru 指最近使用的计算结果会保留在缓存中。


该装饰器的原型如下:


@functools.lru_cache(maxsize=None, typed=False)
复制代码


  • maxsize:最多缓存的次数,如果为 None,则无限制,设置为 2n 时,性能最佳;

  • typed:如果设置为 True(注意,在 functools32 中没有此参数),则不同参数类型的调用将分别缓存,例如 f(3) 和 f(3.0)。


接下来通过菲波那切数列的递归展示有无 lru_cache 的区别。


from functools import lru_cacheimport timeit
@lru_cache()def factorial(n): return 1 if n <= 1 else n * factorial(n - 1)
a = timeit.timeit(stmt="factorial(20)", setup='from __main__ import factorial', number=100000)print(a)
复制代码


  • 不带 lru_cache 耗时:0.2;

  • 带 耗时:0.06


差异明显,这是因为每次执行 factorial 时,都会检查由装饰器维护的缓存池,如果值存在,直接获取对应的结果,避免重复计算。


一般的结论是,对于需要重复计算同一组值的应用,使用装饰器 @lru_cache 可以大幅度提升性能。

reduce 函数

reduce 函数也是高阶函数,它可以将可迭代对象中相邻的两个值通过指定函数结合在一起,因此 sumlenmaxmin 都可以看做是 reduce 函数的特殊形式。


reduce 函数的定义:


reduce(function, sequence [, initial] ) -> value
复制代码


function参数:是一个有两个参数的函数,reduce 依次从 sequence 中取一个元素,和上一次调用 function 的结果做参数再次调用 function。如果第一次没有指定 initial,则默认使用 sequence 的第一个元素与下一个元素一同传入二元 function 函数中去执行。


读起来有点绕,直接看案例即可。


from functools import reduce
def add(x, y): return x + y
a = reduce(add, [1, 2, 3, 4])print(a)
复制代码


initial 参数表示初始值,默认情况下是使用序列的第一个值。


from functools import reduce
a = reduce(lambda x, y: x + y, [1, 2, 3, 4], 2)print(a)
复制代码


下面为大家展示如何使用 reduce 实现 sumlen 等函数。


from functools import reduce
data = [1, 2, 3, 4]
sum = lambda data: reduce(lambda x, y: x + y, data, 0)count = lambda data: reduce(lambda x, y: x + 1, data, 0)
min = lambda data: reduce(lambda x, y: x if x < y else y, data)
a = sum(data)b = count(data)c = min(data)print(a, b, c)
复制代码


还可以使用 reduce 函数与 partical 函数实现 sum 函数,代码如下:


from functools import reduce, partial
data = [1, 2, 3, 4]
sum = partial(reduce, lambda x, y: x + y)a = sum(data)print(a)
复制代码

写在后面

以上内容就是本文的全部内容。


更多精彩


发布于: 刚刚阅读数: 2
用户头像

爬虫 100 例作者,蓝桥签约作者,博客专家 2021.02.06 加入

6 年产品经理+教学经验,3 年互联网项目管理经验; 互联网资深爱好者; 沉迷各种技术无法自拔,导致年龄被困在 25 岁; CSDN 爬虫 100 例作者。 个人公众号“梦想橡皮擦”。

评论

发布
暂无评论
4. Python 函数式编程之 functools 模块初体验