functools模块是Python标准库中用于高阶函数操作的模块,提供了一系列用于函数操作的工具,包括函数装饰器、部分函数应用、函数属性管理等。这些工具可以帮助开发者编写更简洁、更高效的函数式Python代码。
@functools.cached_property
(Python 3.8+)将方法转换为缓存的属性,只计算一次,然后作为实例的常规属性缓存:
import functools
class Data:
def __init__(self, n):
self.n = n
@functools.cached_property
def expensive_computation(self):
print("Computing...")
return self.n * 2
d = Data(10)
print(d.expensive_computation) # Computing... 20
print(d.expensive_computation) # 20 (不再计算)
@functools.lru_cache(maxsize=128, typed=False)
函数装饰器,提供最近最少使用(LRU)缓存:
@functools.lru_cache(maxsize=32)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
print(fib(30)) # 第一次计算
print(fib(30)) # 从缓存中获取
# 查看缓存信息
print(fib.cache_info()) # CacheInfo(hits=28, misses=31, maxsize=32, currsize=31)
@functools.total_ordering
类装饰器,自动填充缺失的比较方法:
@functools.total_ordering
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __eq__(self, other):
return self.grade == other.grade
def __lt__(self, other):
return self.grade < other.grade
a = Student('Alice', 85)
b = Student('Bob', 90)
print(a <= b) # True
print(a > b) # False
functools.partial(func, /, *args, **keywords)
部分函数应用,固定函数的部分参数:
def power(base, exponent):
return base ** exponent
square = functools.partial(power, exponent=2)
cube = functools.partial(power, exponent=3)
print(square(5)) # 25
print(cube(5)) # 125
functools.partialmethod(func, /, *args, **keywords)
类似于partial,但用于类方法:
class Cell:
def __init__(self):
self.alive = False
def set_state(self, state):
self.alive = state
set_alive = functools.partialmethod(set_state, True)
set_dead = functools.partialmethod(set_state, False)
cell = Cell()
cell.set_alive()
print(cell.alive) # True
functools.reduce(function, iterable[, initializer])
将两个参数的函数从左到右累积地应用到iterable的项:
numbers = [1, 2, 3, 4, 5]
product = functools.reduce(lambda x, y: x * y, numbers)
print(product) # 120 (1*2*3*4*5)
# 带初始值
sum_sq = functools.reduce(lambda x, y: x + y**2, numbers, 0)
print(sum_sq) # 55 (0 + 1 + 4 + 9 + 16 + 25)
functools.singledispatch
将函数转换为单分派泛函数:
@functools.singledispatch
def process(data):
raise NotImplementedError("Unsupported type")
@process.register(str)
def _(data):
return f"Processing string: {data}"
@process.register(int)
def _(data):
return f"Processing integer: {data}"
print(process("hello")) # Processing string: hello
print(process(42)) # Processing integer: 42
print(process([])) # NotImplementedError
functools.singledispatchmethod
(Python 3.8+)类似于singledispatch,但用于类方法:
class Processor:
@functools.singledispatchmethod
def process(self, data):
raise NotImplementedError("Unsupported type")
@process.register(str)
def _(self, data):
return f"Processing string: {data}"
@process.register(int)
def _(self, data):
return f"Processing integer: {data}"
p = Processor()
print(p.process("hello")) # Processing string: hello
print(p.process(42)) # Processing integer: 42
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
更新包装函数,使其看起来像被包装的函数:
def decorator(func):
@functools.wraps(func) # 等同于手动调用update_wrapper
def wrapper(*args, **kwargs):
"""Wrapper docstring"""
print("Before call")
result = func(*args, **kwargs)
print("After call")
return result
return wrapper
@decorator
def example():
"""Example docstring"""
print("Inside example")
print(example.__name__) # 'example' (而不是'wrapper')
print(example.__doc__) # 'Example docstring' (而不是'Wrapper docstring')
@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
装饰器工厂,用于调用update_wrapper的便捷方式:
def my_decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
print(f"Calling {f.__name__}")
return f(*args, **kwargs)
return wrapper
@my_decorator
def say_hello(name):
"""Greet someone"""
return f"Hello, {name}!"
print(say_hello.__name__) # 'say_hello'
print(say_hello.__doc__) # 'Greet someone'
functools.compose(*functions)
(Python中没有内置,但可以自己实现)虽然Python标准库中没有直接提供compose函数,但可以用reduce实现:
def compose(*funcs):
return functools.reduce(lambda f, g: lambda x: f(g(x)), funcs)
def add_one(x):
return x + 1
def square(x):
return x * x
add_one_and_square = compose(square, add_one)
print(add_one_and_square(2)) # 9 ((2+1)^2)
@functools.lru_cache(maxsize=100)
def get_user_info(user_id):
print(f"Fetching user {user_id} from API")
# 模拟API调用
return {"id": user_id, "name": f"User {user_id}"}
print(get_user_info(1)) # Fetching user 1 from API
print(get_user_info(1)) # 从缓存获取
import time
def timed_lru_cache(seconds, maxsize=128):
def wrapper(func):
func = functools.lru_cache(maxsize=maxsize)(func)
func.lifetime = seconds
func.expiration = time.monotonic() + seconds
@functools.wraps(func)
def wrapped(*args, **kwargs):
if time.monotonic() >= func.expiration:
func.cache_clear()
func.expiration = time.monotonic() + func.lifetime
return func(*args, **kwargs)
return wrapped
return wrapper
@timed_lru_cache(seconds=10)
def get_data():
print("Fetching fresh data")
return time.time()
print(get_data()) # Fetching fresh data
print(get_data()) # 从缓存获取 (10秒内)
def retry(max_attempts=3, delay=1):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
if attempts == max_attempts:
raise
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=3, delay=1)
def unreliable_api_call():
if random.random() < 0.7:
raise ValueError("API failed")
return "Success"
functools模块提供了:
lru_cache
, cached_property
partial
, partialmethod
reduce
, wraps
, update_wrapper
singledispatch
, singledispatchmethod
total_ordering
通过合理使用functools模块具有如下优势: