12 functools函数工具
写Python代码的时候,有些操作很常见——给函数加缓存避免重复计算、固定函数的部分参数、保留装饰器里函数的元信息……这些都可以用functools模块来搞定。
functools提供的是"高阶函数"——操作其他函数的函数。它能让你的代码更简洁、更高效。
一、缓存装饰器
1.1 lru_cache()
LRU缓存,自动缓存函数的返回值,相同参数再次调用时直接返回缓存结果。
python
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 第一次调用会计算
print(fibonacci(100)) # 354224848179261915075
# 再次调用直接返回缓存
print(fibonacci(100)) # 354224848179261915075
# 查看缓存统计
print(fibonacci.cache_info())
# CacheInfo(hits=98, misses=101, maxsize=128, currsize=101)
# 清除缓存
fibonacci.cache_clear()maxsize参数设置缓存大小,None表示无限制。参数必须是可哈希的。
1.2 cache()
无限制缓存(3.9+),比lru_cache(maxsize=None)更轻量。
python
from functools import cache
@cache
def expensive_function(x):
print(f"计算 {x}...")
return x * x
expensive_function(4) # 计算 4... → 16
expensive_function(4) # 直接返回16,不会打印1.3 cached_property()
缓存属性(3.8+),只计算一次,之后直接返回缓存值。
python
from functools import cached_property
class DataProcessor:
def __init__(self, data):
self.data = data
@cached_property
def processed(self):
print("处理数据...")
return [x * 2 for x in self.data]
processor = DataProcessor([1, 2, 3])
print(processed) # 处理数据... → [2, 4, 6]
print(processed) # 直接返回[2, 4, 6],不会打印二、偏函数
2.1 partial()
固定函数的部分参数,返回一个新的可调用对象。
python
from functools import partial
def power(base, exponent):
return base ** exponent
# 固定exponent为2
square = partial(power, exponent=2)
print(square(5)) # 25
# 固定exponent为3
cube = partial(power, exponent=3)
print(cube(5)) # 125
# 固定第一个参数
base2_power = partial(power, 2)
print(base2_power(10)) # 10242.2 实际应用场景
python
from functools import partial
from datetime import datetime
# 固定日期格式
format_date = partial(datetime.now().strftime, "%Y-%m-%d")
print(format_date()) # 2026-06-13
# 固定日志级别
import logging
logger = logging.getLogger(__name__)
error_log = partial(logger.error, "模块A")
error_log("发生错误") # 等价于logger.error("模块A", "发生错误")三、装饰器工具
3.1 wraps()
保留被装饰函数的元信息(__name__、__doc__等)。
python
from functools import wraps
def my_decorator(func):
@wraps(func) # 保留func的元信息
def wrapper(*args, **kwargs):
print("装饰器执行")
return func(*args, **kwargs)
return wrapper
@my_decorator
def greet(name):
"""打招呼函数"""
return f"Hello, {name}"
# 没有@wraps时,这些会显示wrapper的信息
print(greet.__name__) # greet(不是wrapper)
print(greet.__doc__) # 打招呼函数3.2 total_ordering()
自动补全比较方法,只需定义__eq__和一个排序方法。
python
from functools import total_ordering
@total_ordering
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __eq__(self, other):
return self.score == other.score
def __lt__(self, other):
return self.score < other.score
# total_ordering会自动生成__le__、__gt__、__ge__
s1 = Student("大志", 85)
s2 = Student("小明", 92)
print(s1 < s2) # True
print(s1 > s2) # False
print(s1 >= s2) # False3.3 singledispatch()
单分派泛型函数,根据第一个参数的类型分派到不同实现。
python
from functools import singledispatch
@singledispatch
def process(data):
print(f"处理通用数据: {data}")
@process.register(int)
def _(data):
print(f"处理整数: {data}")
@process.register(str)
def _(data):
print(f"处理字符串: {data}")
@process.register(list)
def _(data):
print(f"处理列表: {data}")
process(42) # 处理整数: 42
process("hello") # 处理字符串: hello
process([1, 2]) # 处理列表: [1, 2]
process(3.14) # 处理通用数据: 3.14四、累积归约
4.1 reduce()
对序列进行累积计算。
python
from functools import reduce
# 累加
result = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
print(result) # 15
# 累乘
result = reduce(lambda x, y: x * y, [1, 2, 3, 4, 5])
print(result) # 120
# 带初始值
result = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 100)
print(result) # 115
# 求最大值
result = reduce(lambda x, y: x if x > y else y, [3, 1, 4, 1, 5, 9])
print(result) # 94.2 实际应用
python
from functools import reduce
# 合并多个字典
dicts = [{"a": 1}, {"b": 2}, {"c": 3}]
merged = reduce(lambda x, y: {**x, **y}, dicts)
print(merged) # {'a': 1, 'b': 2, 'c': 3}
# 嵌套属性访问
def deep_get(obj, *keys):
return reduce(lambda d, key: d[key], keys, obj)
data = {"user": {"profile": {"name": "大志"}}}
print(deep_get(data, "user", "profile", "name")) # 大志五、其他实用工具
5.1 cmp_to_key()
把旧式比较函数转换为sorted()可用的key函数。
python
from functools import cmp_to_key
# 旧式比较函数
def compare(a, b):
return (a > b) - (a < b)
# 转换为key函数
data = [3, 1, 4, 1, 5, 9]
sorted_data = sorted(data, key=cmp_to_key(compare))
print(sorted_data) # [1, 1, 3, 4, 5, 9]5.2 update_wrapper()
手动更新包装函数的元信息(wraps()就是基于它实现的)。
python
from functools import update_wrapper
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
update_wrapper(wrapper, func)
return wrapper六、Python 3.14新特性
6.1 Placeholder
partial()的新哨兵,支持预填充任意位置参数。
python
from functools import partial, Placeholder
def func(a, b, c):
return (a, b, c)
# 预填充第二个参数
p = partial(func, Placeholder, "固定值", Placeholder)
print(p(1, 3)) # (1, '固定值', 3)七、实用技巧
7.1 计时装饰器
python
from functools import wraps
import time
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} 耗时: {elapsed:.4f}秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
slow_function() # slow_function 耗时: 1.0012秒7.2 重试装饰器
python
from functools import wraps
def retry(max_attempts=3):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
print(f"重试 {attempt + 1}/{max_attempts}")
return wrapper
return decorator
@retry(max_attempts=3)
def unstable_function():
import random
if random.random() < 0.5:
raise ValueError("随机错误")
return "成功"7.3 缓存优化递归
python
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 即使n很大也能快速计算
print(fibonacci(500))八、总结
functools的核心函数:
| 函数 | 用途 |
|---|---|
lru_cache() / cache() | 函数结果缓存 |
cached_property() | 属性缓存 |
partial() | 偏函数,固定部分参数 |
wraps() | 保留被装饰函数的元信息 |
reduce() | 累积归约 |
total_ordering() | 自动生成比较方法 |
singledispatch() | 类型分派 |
cmp_to_key() | 比较函数转key函数 |
最常用的就是lru_cache()、partial()、wraps()这三个,覆盖了大部分场景。