functools
问题
functools 模块有哪些常用工具?lru_cache、partial、reduce、singledispatch 怎么用?
答案
lru_cache — 函数缓存
from functools import lru_cache, cache
@lru_cache(maxsize=128) # LRU 缓存,最多 128 个结果
def fibonacci(n: int) -> int:
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(100)
print(fibonacci.cache_info()) # CacheInfo(hits=98, misses=101, ...)
fibonacci.cache_clear() # 清除缓存
# Python 3.9+:无限缓存
@cache # 等价于 @lru_cache(maxsize=None)
def expensive(x):
return x ** 2
partial — 偏函数
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5)) # 25
print(cube(5)) # 125
# 常用于回调
import json
parse_json = partial(json.loads, encoding="utf-8")
reduce — 归约
from functools import reduce
# 累积运算
result = reduce(lambda acc, x: acc + x, [1, 2, 3, 4, 5]) # 15
result = reduce(lambda acc, x: acc * x, [1, 2, 3, 4, 5]) # 120
# 带初始值
result = reduce(lambda acc, x: acc + x, [1, 2, 3], 10) # 16
singledispatch — 单分派泛函数
from functools import singledispatch
@singledispatch
def process(data):
raise TypeError(f"不支持的类型: {type(data)}")
@process.register(str)
def _(data: str):
return data.upper()
@process.register(list)
def _(data: list):
return [process(item) for item in data]
@process.register(int)
def _(data: int):
return data * 2
print(process("hello")) # "HELLO"
print(process(42)) # 84
print(process([1, "a"])) # [2, "A"]
wraps — 保留元信息
from functools import wraps
def decorator(func):
@wraps(func) # 保留原函数的 __name__、__doc__ 等
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
常见面试问题
Q1: lru_cache 的参数必须是可哈希的吗?
答案:
是。lru_cache 用参数的哈希值作为缓存键,所以参数必须是可哈希类型。list、dict 等可变类型不可哈希,不能直接作为被缓存函数的参数。
@lru_cache
def func(lst): # ❌ TypeError: unhashable type: 'list'
pass
@lru_cache
def func(t: tuple): # ✅ tuple 可哈希
pass