77、Python之函数式编程:一文搞懂functools模块的核心应用

引言

Python作为一种支持多范式的编程语言,除了在“一切皆对象”的理念支持下的,函数对象也是一等公民、各种高阶函数的自然实现、lambda表达式快速编写纯函数之外。还有一个内置的模块functools,能够更好地支持我们在Python中应用函数式编程。

本文的主要内容有:

1、functools模块概览

2、偏函数

3、自定义排序

4、属性缓存

5、其他已经介绍过的功能

functools模块概览

functools模块是Python标准库中的一部分,提供了一系列高阶函数和操作函数的工具,涵盖了偏函数、聚合操作、性能优化、多态处理、装饰器开发、自定义排序和属性缓存等多种功能。

通过理解和使用这些工具,可以大大提高代码的灵活性、性能和可维护性。无论是函数式编程,还是面向对象编程等,在日常的开发任务中,functools都是一个不可或缺的利器。

偏函数

functools模块有很多重要的功能,其中一个就是偏函数(Partial function)。

需要注意的是,这里的偏函数与数学意义上的偏函数(偏导数)是不一样的。

Python中的偏函数是用于对函数固定参数的函数,作用就是把一个函数中的某些参数固定住,类似于设置默认值的逻辑,返回一个新的函数,从而使得多元函数的调用变得更加简单,从而对使用者更加友好。

先看下定义:

aed5d0cef0323cda76cd14d44dfd405f.jpeg

然后以实际代码看一下partial的使用:

from functools import partial


def add(x, y, z):
    return x + y + z


add_one_two = partial(add, 1, 2)
print(add_one_two)
print(add_one_two(3))

执行结果:

f5860c4726ea4179c535ff0cf62b4477.jpeg

需要说明的是,偏函数虽然与柯里化比较相似,但是,两者在使用上还是有所区别的。偏函数是固定部分参数,直接生成新的函数。而柯里化,是逐步进行函数参数的传递,嵌套函数,每个函数只接收一个参数。在调用上,偏函数是一次性传递所有剩余参数,柯里化是逐层传递每一个参数。

自定义排序

functools模块提供了一个total_ordering的装饰器,用于自动生成缺失的排序方法。

首先看下定义:

fb4f652c691015a28711a740c0b556ce.jpeg

只要定义比较方法,比如<、>、<=、>=中的一个方法,该装饰器可以帮助自动推导出另外几个方法。

还是直接看代码:

from functools import total_ordering


@total_ordering
class DaGongRen:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __lt__(self, other):
        return self.age < other.age

    # == / != 还是要自己手工定义的
    def __eq__(self, other):
        return self.age == other.age


zs = DaGongRen('张三', 18)
ls = DaGongRen('李四', 23)
ww = DaGongRen('王五', 18)

print(zs < ls)
print(zs <= ls)
print(zs > ls)
print(zs >= ls)
print(zs == ls)
print(zs != ls)
print(zs == ww)

执行结果:

0938f2349812d2bd4ac9c9740add50fa.jpeg

可以看到,我们在代码中只定义了__lt__方法,total_ordering装饰器自动根据该方法实现了另外3个用于比较的方法。

需要说明的是,==、!=还是自行定义__eq__方法来实现。

属性缓存

在面向对象中,我们介绍过property属性装饰器,有些计算的属性,如果比较消耗性能,还可以使用functools中提供的cached_property来实现计算结果的缓存。

直接以代码为例:

from functools import cached_property
from math import pi


class Circle:
    def __init__(self, radius):
        self.radius = radius

    @cached_property
    def area(self):
        print('进行圆的面积计算')
        return pi * self.radius * self.radius


circle = Circle(10)
print(circle.area)
print('=' * 20)
print(circle.area)

执行结果:

55bee97fb9c7d06ceae4020cfb9c89a1.jpeg

可以看到,第二次调用时,并没有执行area()方法的调用。

其他已经介绍过的功能

functools中还有其他功能,我们在前面的文章中都已经介绍过了,这里就不展开详细说明了,只是简单列举回顾一下:

1、functools.reduce:用于将一个二元操作函数应用于序列,实现累计地将序列元素计算合并为一个结果。

2、functools.lru_cache:装饰器,用于缓存函数的计算结果,从而提高性能,lru是Least Recently Used的缩写,表示缓存采用的最近最少使用的缓存置换策略。

3、functools.singledispatch:装饰器,用于实现单分派泛函数,允许根据第一个参数的类型调用不同的函数实现,近似实现其他语言中的函数重载。

4、functolls.wraps:装饰器,主要用于确保装饰器不修改被装饰函数的元数据。

总结

本文详细介绍了functools中的各个核心功能的使用,包括偏函数、自定义排序、缓存属性等。functools模块,不仅可以用于函数式编程,面向对象编程中,也可以发挥巨大的作用。

感谢您的拨冗阅读,希望对您有所帮助。

97132d8df638f170fda1e121797eab57.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南宫理的日知录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值