本文目录导读:

我来详细讲解 Python 装饰器传参的几种常见方式。
基础装饰器(无参数)
def simple_decorator(func):
def wrapper(*args, **kwargs):
print("执行前")
result = func(*args, **kwargs)
print("执行后")
return result
return wrapper
@simple_decorator
def greet(name):
return f"你好, {name}"
# 使用
print(greet("Alice"))
# 输出:
# 执行前
# 执行后
# 你好, Alice
装饰器本身传参
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def say_hello(name):
print(f"Hello, {name}")
# 使用
say_hello("Bob")
# 输出:
# Hello, Bob
# Hello, Bob
# Hello, Bob
向被装饰函数传参
def validate_args(*expected_types):
def decorator(func):
def wrapper(*args, **kwargs):
# 验证位置参数的类型
for arg, expected_type in zip(args, expected_types):
if not isinstance(arg, expected_type):
raise TypeError(f"参数 {arg} 类型错误,期望 {expected_type}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_args(int, int)
def add(a, b):
return a + b
# 使用
print(add(1, 2)) # 3
# print(add(1, "2")) # 会抛出 TypeError
实际案例:日志装饰器
import functools
import time
def log(logger=None, level='INFO'):
"""
带参数的日志装饰器
:param logger: 日志对象
:param level: 日志级别
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
# 记录调用信息
if logger:
log_msg = f"[{level}] 调用 {func.__name__} - args: {args}, kwargs: {kwargs}"
logger.log(log_msg)
else:
print(f"[{level}] 调用 {func.__name__}")
try:
result = func(*args, **kwargs)
elapsed = time.time() - start_time
if logger:
logger.log(f"[{level}] {func.__name__} 执行完成,耗时: {elapsed:.4f}s")
else:
print(f"[{level}] {func.__name__} 执行完成,耗时: {elapsed:.4f}s")
return result
except Exception as e:
if logger:
logger.log(f"[ERROR] {func.__name__} 执行失败: {e}")
raise
return wrapper
return decorator
# 使用示例
class SimpleLogger:
def log(self, msg):
print(f"Logger: {msg}")
@log(logger=SimpleLogger(), level='DEBUG')
def calculate(x, y):
return x * y
calculate(5, 3)
缓存装饰器
import functools
def cache(maxsize=128):
"""
带最大缓存大小的缓存装饰器
"""
def decorator(func):
cache_dict = {}
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 创建缓存键
key = str(args) + str(sorted(kwargs.items()))
if key in cache_dict:
print(f"使用缓存: {key}")
return cache_dict[key]
result = func(*args, **kwargs)
# 缓存管理
if len(cache_dict) >= maxsize:
# 移除最早添加的项
first_key = next(iter(cache_dict))
del cache_dict[first_key]
cache_dict[key] = result
return result
return wrapper
return decorator
@cache(maxsize=3)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 使用
print(fibonacci(10)) # 计算并缓存
print(fibonacci(10)) # 使用缓存
同时处理装饰器和被装饰函数参数
def permission_required(permission):
"""
权限验证装饰器
"""
def decorator(func):
def wrapper(user, *args, **kwargs):
if not user.get(permission, False):
raise PermissionError(f"用户没有 {permission} 权限")
return func(user, *args, **kwargs)
return wrapper
return decorator
@permission_required("admin")
def delete_user(user, user_id):
print(f"管理员 {user['name']} 删除用户 {user_id}")
# 使用
admin = {"name": "Admin", "admin": True}
user = {"name": "User", "admin": False}
delete_user(admin, 1) # 正常执行
# delete_user(user, 2) # 抛出 PermissionError
高级案例:重试装饰器
import random
import time
def retry(max_retries=3, delay=1, backoff=2):
"""
重试装饰器
:param max_retries: 最大重试次数
:param delay: 初始延迟时间
:param backoff: 延迟倍数
"""
def decorator(func):
def wrapper(*args, **kwargs):
current_delay = delay
last_exception = None
for attempt in range(max_retries + 1):
try:
return func(*args, **kwargs)
except Exception as e:
last_exception = e
if attempt < max_retries:
print(f"第 {attempt + 1} 次重试,等待 {current_delay} 秒...")
time.sleep(current_delay)
current_delay *= backoff
raise last_exception
return wrapper
return decorator
@retry(max_retries=3, delay=1, backoff=2)
def unstable_api_call():
if random.random() < 0.7: # 70% 概率失败
raise ConnectionError("连接失败")
return "成功"
# 使用
try:
result = unstable_api_call()
print(f"结果: {result}")
except Exception as e:
print(f"最终失败: {e}")
参数传递示意图
@decorator(args) # 装饰器参数
def func(x, y): # 被装饰函数参数
pass
等效于:
decorator(args)(func)(x, y)
关键要点
-
三层嵌套结构:
- 最外层:接收装饰器参数
- 中间层:接收被装饰函数
- 内层:接收被装饰函数的参数
-
参数优先级:
- 装饰器参数:在装饰时确定
- 函数参数:在调用时传递
-
保持函数签名:
- 使用
@functools.wraps(func)保留原函数信息
- 使用
-
灵活设计:
- 可以组合多个装饰器
- 支持默认参数
- 考虑错误处理
通过这些案例,你可以根据实际需求灵活设计带参数的 Python 装饰器。