partial:固定部分参数
把多参数函数变成"少参数函数":
from functools import partial
def power(base, exp):
return base ** exp
square = partial(power, exp=2) # 固定 exp=2
cube = partial(power, exp=3)
square(5) # 25
cube(5) # 125
实战场景:
import requests
from functools import partial
# 所有 GET 请求都加同一个 header
get = partial(requests.get, headers={"X-Token": "abc"})
get("https://api.example.com/users")
get("https://api.example.com/orders")
lru_cache:函数级缓存
加一行装饰器,重复调用秒返:
from functools import lru_cache
@lru_cache(maxsize=128)
def fib(n):
if n < 2: return n
return fib(n - 1) + fib(n - 2)
fib(100) # 不缓存的话天荒地老;加了瞬间出
⚠️ 参数必须可哈希(不能是 list / dict)。
清缓存:fib.cache_clear()。看命中率:fib.cache_info()。
cache(Python 3.9+):无大小限制
from functools import cache
@cache
def fib(n):
...
简化版 lru_cache(maxsize=None)——如果不在意缓存撑大用这个。
wraps:写装饰器必备
不加的话,被装饰的函数会"丢失身份":
from functools import wraps
def log(func):
@wraps(func) # 复制 func 的 __name__ / __doc__ 等
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log
def add(a, b):
"""加法"""
return a + b
print(add.__name__) # 'add' (没加 wraps 会变成 'wrapper')
print(add.__doc__) # '加法'
写装饰器永远加 @wraps。
reduce
from functools import reduce
reduce(lambda a, b: a + b, [1, 2, 3, 4]) # 10
讲过了,但放进全家桶提一句——它住在 functools 里。
singledispatch:基于类型的函数重载
from functools import singledispatch
@singledispatch
def show(arg):
print(f"默认: {arg}")
@show.register(int)
def _(arg):
print(f"整数: {arg * 2}")
@show.register(str)
def _(arg):
print(f"字符串: {arg.upper()}")
@show.register(list)
def _(arg):
print(f"列表,长度 {len(arg)}")
show(42) # 整数: 84
show("hello") # 字符串: HELLO
show([1, 2, 3]) # 列表,长度 3
show(3.14) # 默认: 3.14
类似面向对象的"多态",但写法更函数式。
reduce vs sum 的取舍
reduce(lambda a, b: a + b, nums) # 啰嗦
sum(nums) # 简洁,且更快
Python 内置往往比 reduce 更地道——只有真没内置时再用 reduce。
下一篇是装饰器原理(已写)。再下一篇讲装饰器进阶。