An Introduction to Python's functools Module and Its Common Utilities
This article introduces Python's functools module, explaining key utilities such as partial functions, lru_cache, update_wrapper, wraps, cmp_to_key, singledispatch, FunctionTool, cache, and partialmethod, and provides practical code examples demonstrating how to create preset request functions, cache results, update signatures, and implement polymorphic behavior.
Python's functools module is a standard library that provides a collection of higher‑order functions and decorators for functional programming, including tools for creating partial functions, caching results, and preserving function metadata.
Partial functions (partial) allow you to pre‑set some arguments of a callable, simplifying repeated calls. Example:
import requests
from functools import partial
# Create a request function with a default timeout
send_request = partial(requests.get, timeout=5)
response = send_request("https://api.example.com/data")
print("响应内容:", response.json()) # 响应内容: {'key': 'value'}Cache decorator (lru_cache) memoizes function results to avoid redundant computation. Example:
import requests
from functools import lru_cache
@lru_cache(maxsize=32)
def get_user(id):
response = requests.get(f"https://api.example.com/user/{id}")
return response.json()
user = get_user(1)
print("用户:", user) # 用户: {'id': 1, 'name': 'User 1'}Updating function signatures (update_wrapper and wraps) keeps the original function's metadata after decoration. Example:
import requests
from functools import wraps
def log_request(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("发送请求:", args[0])
return func(*args, **kwargs)
return wrapper
@log_request
def send_request(url):
"""发送请求并返回响应"""
response = requests.get(url)
return response.json()
result = send_request("https://api.example.com/data")
# 输出:
# 发送请求: https://api.example.com/data
# 响应内容: {'key': 'value'}Comparison function (cmp_to_key) converts an old‑style comparator into a key function for sorting. Example:
from functools import cmp_to_key
def compare_by_age(u1, u2):
return (u1['age'] > u2['age']) - (u1['age'] < u2['age'])
users = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 30},
{"name": "Charlie", "age": 20}
]
sorted_users = sorted(users, key=cmp_to_key(compare_by_age), reverse=True)
for user in sorted_users:
print("用户:", user)
# 输出:
# 用户: {'name': 'Bob', 'age': 30}
# 用户: {'name': 'Alice', 'age': 25}
# 用户: {'name': 'Charlie', 'age': 20}Single‑dispatch (singledispatch) enables type‑based polymorphic functions. Example:
from functools import singledispatch
@singledispatch
def process_data(data):
raise NotImplementedError("Unsupported data type")
@process_data.register(int)
def _(data):
return f"处理整数 {data}"
@process_data.register(str)
def _(data):
return f"处理字符串 '{data}'"
result_int = process_data(123)
result_str = process_data("Hello")
print(result_int) # 处理整数 123
print(result_str) # 处理字符串 'Hello'FunctionTool is a base class for building custom function utilities. Example:
from functools import FunctionTool
class MyTool(FunctionTool):
def __init__(self, func):
super().__init__(func)
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
return super().__call__(*args, **kwargs)
@MyTool
def add(a, b):
"""添加两个数字"""
return a + b
result = add(1, 2)
print("结果:", result) # 结果: 3
print("调用次数:", add.calls) # 调用次数: 1Cache decorator (cache) provides a simple memoization without size limits. Example:
from functools import cache
@cache
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
result = fibonacci(10)
print("斐波那契数列第10项:", result) # 斐波那契数列第10项: 55Partial method (partialmethod) creates class‑method partials. Example:
from functools import partialmethod
class MyClass:
def __init__(self, value):
self.value = value
def echo(self, prefix):
return f"{prefix}: {self.value}"
echo_with_prefix = partialmethod(echo, "Prefix")
instance = MyClass("Hello World")
print(instance.echo_with_prefix()) # Prefix: Hello WorldTest Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.