functools

关注
义项:Python标准库函数工具模块
functools

functools是Python标准库中面向高阶函数的模块,其中收录的工具可以作用于函数或返回新的函数,任何可调用对象都能被视为该模块所处理的函数[1][2]。它提供偏函数构造、结果缓存、装饰器辅助、类型分派等工具,使函数的部分参数可以固定、重复计算可以复用,从而简化调用接口并降低高开销函数的运行成本[3]。该模块自Python 2.5起进入标准库,此后随版本迭代不断扩充[4]。

百科 图文
目录
  1. 定义
  2. 原理
  3. 发展历程
  4. 应用
  5. 局限
  6. 参见

定义

functools是Python标准库提供的一个模块,用于高阶函数与可调用对象上的操作。所谓高阶函数,是指那些作用于其他函数或者返回其他函数的函数;就本模块的用途而言,任何可调用对象都可以当作函数来处理[1][5]。

该模块不引入新的语法,而是以普通函数和装饰器的形式给出工具,因此可以配合装饰器、闭包等既有机制使用[3]。其中partial用于实现部分函数应用,reduce用于把可迭代对象归约为单个值,lru_cache与cache用于记忆化,singledispatch用于把函数改造成单分派泛型函数,wraps与update_wrapper则服务于装饰器的编写[1][6]。

原理

偏函数应用的基本思路是固定原函数的一部分参数,得到一个参数更少的新可调用对象。functools.partial返回的partial对象保存原始函数、已绑定的位置参数和关键字参数;此后调用该对象时,新传入的位置参数会接在已绑定参数之后,新传入的关键字参数则会覆盖原有同名项[7]。

记忆化缓存依据参数查找结果。以lru_cache为例,被包装的函数附带cache_info()、cache_clear()与cache_parameters()等接口,可分别查看命中与未命中情况、清空缓存、读取配置;原始函数可通过__wrapped__属性访问,便于内省或绕过缓存重新装饰[1]。由于底层用字典保存结果,传给被包装函数的位置参数和关键字参数必须可哈希,否则无法作为缓存键[1]。

缓存淘汰采用最近最少使用(LRU)策略,其有效性依赖于近期的调用能够较好地预测接下来的调用,例如新闻站点上最受关注的文章往往逐日变化;缓存容量上限则避免长时间运行的进程无限占用内存[1][2]。归约操作按从左到右的顺序进行,reduce把两参数函数反复施加到序列元素上,左参数为累积值,右参数为当前元素,并可选的initial作为初始值参与计算[5]。

单分派泛型函数按照第一个参数的类型选择实现。用singledispatch装饰的函数是面向object类型的默认实现,为其类型注册的具体实现通过register()属性加入;找不到匹配类型时,按方法解析顺序回溯到更通用的实现,已注册实现的查询结果会被缓存[8][9]。

发展历程

该模块的起点是PEP 309。2003年2月8日,Peter Harris提交了关于部分函数应用的提案,最初建议的标准库模块名为functional;提案被采纳并实施后,社区希望收纳更多作用于函数对象、但与函数式编程无直接关系的工具,于是模块改名为functools,以体现其被拓宽的定位[7][10]。相关补丁在2005年被接受并应用于Python 2.5,使partial、update_wrapper和wraps进入标准库[7][11]。

进入Python 3时代后,模块内容持续增加。cumulative影响较大的变化是reduce的迁入:它原本是Python 2的内置函数,在Python 3中移入functools,并回溯到Python 2.6[12][4]。随后cmp_to_key与total_ordering在3.2版加入,lru_cache同样出现在3.2版,并在3.3版增加typed选项[4]。

后续版本继续补齐工具。单分派泛型函数由PEP 443提出,作者为Łukasz Langa,随Python 3.4进入functools;其功能此前已作为pkgutil中的simplegeneric存在,因此实现基本是整体迁移[9][8]。cached_property在3.8版加入,用于把类方法转换为只计算一次、随后作为普通属性缓存的值;无界的cache装饰器在3.9版加入[5]。

应用

在装饰器编写中,wraps与update_wrapper常被用来让包装函数保留原函数的名称、模块名与文档字符串;若不更新这些元数据,返回函数的属性会反映包装层的定义,而非被装饰函数的定义。

偏函数应用适合在需要更少参数的场景中复用函数。例如把int的base参数固定为2,可以得到一个把二进制字符串转为整数的可调用对象;也可以固定某个乘数,构造出行为类似乘2或乘方的函数[2][6][13]。

缓存工具多用于递归计算与重复的高开销调用。官方文档给出的例子包括用lru_cache配合动态规划计算斐波那契数列,以及对静态网络内容获取函数设定缓存容量,从而避免反复请求[1]。

比较函数转换与类型分派各有适用场合。cmp_to_key把接受两个参数、返回负数、零或正数的旧式比较函数,转换为只接受一个参数并返回排序键的键函数,可配合sorted()、min()、max()等工具使用,主要用于从Python 2迁移过来的代码[2][14]。singledispatch则让同一操作针对不同类型提供不同实现,调用时按首个参数类型自动选取[9]。

局限

缓存类工具并不适用于所有函数。用lru_cache缓存带有副作用的函数、每次调用都需创建不同可变对象的函数(如生成器与异步函数),或者time()、random()这类不纯的函数,都没有实际意义[1]。缓存还会一直持有参数与返回值的引用,直到它们离开缓存或被清空[1]。

多线程下的行为需要留意。lru_cache的缓存是线程安全的,底层数据结构在并发更新期间保持一致,但若另一线程在首次调用完成并写入缓存之前发起额外调用,被包装函数可能被多次执行;在较早的文档中,多线程环境下命中数与未命中数被描述为近似值[1]。

cached_property存在自身的边界。它无法防止多线程使用中出现的竞争条件,取值函数可能在同一实例上运行多次,因此适合取值幂等的情形,如需同步应由使用者在取值函数内部或属性访问处自行加锁;它还会干扰PEP 412键共享字典,可能使实例字典占用更多空间,并且要求实例的__dict__为可变映射,因而对元类以及定义了__slots__而不含__dict__的类型不适用[5]。

参数与分派方面同样有限制。缓存键要求参数可哈希,且参数书写模式不同可能被视作不同调用,例如f(a=1,b=2)与f(b=2,a=1)可能各占一个缓存项;类型区分只作用于直接参数而不涉及其内部内容[1]。singledispatch只依据第一个参数的类型分派,注册表也并非线程安全,面对通过ABC注册造成的歧义分派会直接抛出RuntimeError而不作猜测[9][8]。

参见

  • 装饰器 —— functools中的wraps、lru_cache等多数工具本身即以装饰器形式使用。

  • 高阶函数 —— functools面向的正是作用于或返回其他函数的高阶函数。

  • 偏函数应用 —— partial所实现的功能,即固定原函数的一部分参数。

  • 记忆化 —— lru_cache与cache所依据的缓存策略。

  • 泛型函数 —— singledispatch把普通函数转换为按类型分派的泛型函数。

  • itertools —— Python标准库中与functools并列、常用于函数式编程的模块。

参考资料

  1. functools —— 高阶函数,以及可调用对象上的操作 [引用日期2026-10-14]
  2. functools [引用日期2026-10-14]
  3. functools | Python Standard Library – Real Python [引用日期2026-10-14]
  4. A HITCHHIKER'S GUIDE TO functools [引用日期2026-10-14]
  5. functools --- 可呼叫物件上的高階函式與操作¶ [引用日期2026-10-14]
  6. Python Functools Module - Python Cheat Sheet [引用日期2026-10-14]
  7. PEP 309 -- Partial Function Application [引用日期2026-10-14]
  8. python.org 上的网页 [引用日期2026-10-14]
  9. PEP 443 – 单分派泛型函数 [引用日期2026-10-14]
  10. PEP 309 – 部分函数应用 | peps.python.org [引用日期2026-10-14]
  11. python.org 上的网页 [引用日期2026-10-14]
  12. 【使用Python实现算法】05 标准库(函数式编程模块) [引用日期2026-10-14]
  13. functools,一个好用的 python 工具! [引用日期2026-10-14]
  14. functools [引用日期2026-10-14]
词条评价
词条统计

浏览次数:4 次

阅读量:0 次 · 阅读完成量:0 次

最近更新:2026-10-13T21:25:23Z

历史版本

本条目引用的词条
装饰器 闭包 斐波那契数列 高阶函数 偏函数应用 记忆化 泛型函数 itertools