跳到主要内容

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 用参数的哈希值作为缓存键,所以参数必须是可哈希类型。listdict 等可变类型不可哈希,不能直接作为被缓存函数的参数。

@lru_cache
def func(lst): # ❌ TypeError: unhashable type: 'list'
pass

@lru_cache
def func(t: tuple): # ✅ tuple 可哈希
pass

相关链接