functools 高阶函数与装饰器
一句话
提供高阶函数和可调用对象操作,实现函数缓存、部分应用和泛型分发。
什么时候翻这页
- 需要缓存函数结果以提高性能时
- 创建可复用的工具函数,特别是Agent调用的工具
- 实现多类型参数处理的泛型函数时
- 需要保留原始函数元数据的装饰器开发时
核心概念
- 高阶函数:处理或返回其他函数的函数
- 函数缓存:存储函数计算结果,避免重复计算
- 部分应用:固定函数的部分参数,创建新函数
- 泛型函数:根据参数类型分发到不同实现
- 装饰器:修改或增强函数行为的工具
怎么做
缓存函数结果
# 使用lru_cache缓存函数结果
from functools import lru_cache
@lru_cache(maxsize=32)
def get_pep(num):
'Retrieve text of a Python Enhancement Proposal'
resource = f'https://peps.python.org/pep-{num:04d}'
try:
with urllib.request.urlopen(resource) as s:
return s.read()
except urllib.error.HTTPError:
return 'Not Found'
部分应用函数
# 创建部分应用的函数
from functools import partial
# 创建二进制转换函数
basetwo = partial(int, base=2)
basetwo('10010') # 返回 18
# 使用占位符创建灵活的部分函数
from functools import partial, Placeholder as _
remove = partial(str.replace, _, _, '')
remove('Hello, dear dear world!', ' dear') # 返回 'Hello, world!'
创建泛型函数
# 创建单分派泛型函数
from functools import singledispatch
@singledispatch
def fun(arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg)
# 为不同类型注册不同实现
@fun.register
def _(arg: int, verbose=False):
if verbose:
print("Strength in numbers, eh?", end=" ")
print(arg)
@fun.register
def _(arg: list, verbose=False):
if verbose:
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, elem)
保留函数元数据
# 使用wraps保留原始函数的元数据
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
print('Calling decorated function')
return f(*args, **kwds)
return wrapper
@my_decorator
def example():
"""Docstring"""
print('Called example function')
example.__name__ # 返回 'example'
example.__doc__ # 返回 'Docstring'
命令 / API 速查
| 函数/装饰器 | 描述 | 示例 |
|---|---|---|
@cache | 简单轻量级函数缓存 | @cache def factorial(n): ... |
@lru_cache | 带大小限制的最近最少使用缓存 | @lru_cache(maxsize=128) def func(): ... |
@cached_property | 缓存类属性值 | @cached_property def prop(self): ... |
@total_ordering | 为类实现所有比较方法 | @total_ordering class MyClass: ... |
partial | 创建部分应用的函数 | p = partial(func, arg1, kwarg1=val) |
partialmethod | 创建部分应用的方法 | m = partialmethod(method, arg1) |
reduce | 累积应用函数到序列 | reduce(lambda x,y: x+y, [1,2,3]) |
@singledispatch | 创建单分派泛型函数 | @singledispatch def func(arg): ... |
@singledispatchmethod | 创建单分派泛型方法 | @singledispatchmethod def method(self, arg): ... |
wraps | 保留原始函数元数据 | @wraps(original) def wrapper(): ... |
与 Agent 开发的联系
- 工具缓存:使用
@lru_cache缓存Agent工具调用结果,减少重复计算和API调用 - 工具部分应用:使用
partial创建预配置的工具函数,简化Agent工具调用接口 - 结构化输出:使用
@singledispatch根据输入类型分发到不同的输出格式化函数
初学者易错点
- 缓存装饰器不能用于带有不可哈希参数(如列表、字典)的函数
- 部分应用函数时,占位符(Placeholder)必须全部填充,否则会引发TypeError
- 泛型函数的分派基于第一个参数的类型,不是基于参数数量
- 装饰器会覆盖原始函数的元数据,需要使用
@wraps保留 - 缓存函数可能保持对参数和返回值的引用,导致内存泄漏
相关词条
library-itertools迭代器工具,与functools配合使用library-operator标准运算符函数,常与functools结合python-decoratorsPython装饰器模式详解python-closures闭包与函数工厂python-metaprogrammingPython元编程技术