一、开篇:高阶函数的工具箱
functools模块提供了处理函数和可调用对象的高阶工具。从缓存优化到偏函数,从包装保留到函数重载——它是写出优雅python代码的秘密武器。
⌨️ 核心功能:
from functools import (
reduce, partial, lru_cache, wraps,
total_ordering, singledispatch, cmp_to_key, cached_property
)
二、partial:预填充参数的偏函数
from functools import partial
# partial(func, *args, **kwargs) —— 固定部分参数,创建新函数
# 这是"函数柯里化"在python中的实现
# 基础用法
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2) # 固定exponent=2
cube = partial(power, exponent=3) # 固定exponent=3
print(square(10)) # 100 —— 等价于 power(10, 2)
print(cube(10)) # 1000 —— 等价于 power(10, 3)
# 实际应用:简化回调函数
def log_event(logger, event_type, message, timestamp):
"""记录事件日志"""
print(f"[{timestamp}] {event_type}: {message} (logger={logger})")
# 为特定logger创建便利函数
import time
app_log = partial(log_event, "app")
app_log_error = partial(app_log, "error", timestamp=time.time())
app_log_error("数据库连接失败")
# [1718000000.0] error: 数据库连接失败 (logger=app)
# 应用:数据处理管道
def transform(data, multiplier, offset, round_digits=2):
"""数据转换"""
return round(data * multiplier + offset, round_digits)
# 创建专用转换函数
c_to_f = partial(transform, multiplier=9/5, offset=32, round_digits=1)
f_to_c = partial(transform, multiplier=5/9, offset=-32*5/9, round_digits=1)
print(c_to_f(0)) # 32.0
print(c_to_f(100)) # 212.0
print(f_to_c(32)) # 0.0
三、lru_cache:自动缓存函数结果
from functools import lru_cache, cache
import time
# lru_cache —— 最近最少使用缓存
# cache —— python 3.9+,无限制缓存(等同于lru_cache(maxsize=none))
# 基本用法
@lru_cache(maxsize=128)
def fibonacci(n):
"""计算斐波那契数——带缓存"""
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 第一次调用——计算并缓存
start = time.perf_counter()
print(fibonacci(35))
print(f"首次: {time.perf_counter() - start:.4f}秒")
# 第二次调用——直接返回缓存
start = time.perf_counter()
print(fibonacci(35))
print(f"缓存: {time.perf_counter() - start:.6f}秒")
# 查看缓存统计
print(fibonacci.cache_info())
# cacheinfo(hits=34, misses=36, maxsize=128, currsize=36)
# 清除缓存
fibonacci.cache_clear()
# ⚠️ lru_cache要求参数是可哈希的
# lru_cache装饰器不能用于方法(会导致内存泄漏)
# 实际应用:数据库查询缓存
@lru_cache(maxsize=256)
def get_user_by_id(user_id):
"""模拟数据库查询"""
print(f"查询数据库: user_id={user_id}")
return {"id": user_id, "name": f"用户{user_id}"}
print(get_user_by_id(1)) # 查询数据库
print(get_user_by_id(1)) # 缓存命中——不查数据库
四、wraps:保留函数元信息
from functools import wraps
# 写装饰器时用@wraps保留原函数的元信息
# ❌ 没有@wraps的装饰器
def bad_decorator(func):
def wrapper(*args, **kwargs):
"""这是wrapper的文档"""
return func(*args, **kwargs)
return wrapper
@bad_decorator
def greet(name):
"""向用户打招呼"""
return f"hello, {name}!"
print(greet.__name__) # wrapper —— 名字丢了!
print(greet.__doc__) # 这是wrapper的文档 —— 文档丢了!
# ✅ 使用@wraps的装饰器
def good_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""这是wrapper的文档"""
return func(*args, **kwargs)
return wrapper
@good_decorator
def greet_v2(name):
"""向用户打招呼"""
return f"hello, {name}!"
print(greet_v2.__name__) # greet_v2 —— 正确!
print(greet_v2.__doc__) # 向用户打招呼 —— 正确!
# 💡 @wraps是写装饰器的标配——不加它会导致调试困难
五、其他实用工具
5.1 singledispatch——函数重载
from functools import singledispatch
@singledispatch
def format_output(data):
"""根据参数类型调用不同的格式化函数"""
return str(data)
@format_output.register(list)
def _(data):
return "[" + ", ".join(format_output(item) for item in data) + "]"
@format_output.register(dict)
def _(data):
items = [f"{k}: {format_output(v)}" for k, v in data.items()]
return "{" + ", ".join(items) + "}"
@format_output.register(int)
def _(data):
return f"{data:,}" # 千位分隔
print(format_output(1234567)) # 1,234,567
print(format_output([1, "hello", [2, 3]])) # [1, hello, [2, 3]]
print(format_output({"name": "张三", "age": 25})) # {name: 张三, age: 25}
5.2 cached_property——惰性属性
from functools import cached_property
import time
class dataanalyzer:
def __init__(self, data):
self.data = data
@cached_property
def statistics(self):
"""计算统计信息——只计算一次,结果被缓存"""
print("正在计算统计数据...")
time.sleep(0.5) # 模拟耗时计算
return {
"sum": sum(self.data),
"avg": sum(self.data) / len(self.data),
"min": min(self.data),
"max": max(self.data),
}
analyzer = dataanalyzer([1, 2, 3, 4, 5])
print(analyzer.statistics) # 计算(打印"正在计算...")
print(analyzer.statistics) # 缓存命中(不打印)
# cached_property与property不同——它像实例属性一样直接访问
5.3 total_ordering——自动补全比较方法
from functools import total_ordering
@total_ordering
class version:
"""版本号——只需定义__eq__和__lt__,其余比较方法自动生成"""
def __init__(self, major, minor, patch):
self.major = major
self.minor = minor
self.patch = patch
def __eq__(self, other):
return (self.major, self.minor, self.patch) == \
(other.major, other.minor, other.patch)
def __lt__(self, other):
return (self.major, self.minor, self.patch) < \
(other.major, other.minor, other.patch)
def __repr__(self):
return f"v{self.major}.{self.minor}.{self.patch}"
v1 = version(1, 2, 3)
v2 = version(2, 0, 0)
print(v1 < v2) # true
print(v1 <= v2) # true —— 自动生成!
print(v1 >= v2) # false —— 自动生成!
print(v1 != v2) # true —— 自动生成!
六、总结
functools是编写优雅python函数代码的必备工具箱。从缓存优化到装饰器编写,它让高阶函数编程变得简单而正确。
💡 核心工具:
| 工具 | 一句话 |
|---|---|
| partial() | 固定参数→创建新函数 |
| lru_cache() | 自动缓存→加速递归和重复调用 |
| wraps() | 保留装饰函数的元信息 |
| cached_property | 惰性计算→只算一次 |
| singledispatch | 根据类型选择实现 |
| total_ordering | 补全所有比较方法 |
✅ 写装饰器→用wraps,慢递归→用lru_cache,重复参数→用partial。
到此这篇关于python内置模块functools函数工具使用的文章就介绍到这了,更多相关python functools函数内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论