Skip to content

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))  # 1024

2.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)  # False

3.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)  # 9

4.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()这三个,覆盖了大部分场景。