Python装饰器传参案例如何传递参数

wen python案例 28

本文目录导读:

Python装饰器传参案例如何传递参数

  1. 基础装饰器(无参数)
  2. 装饰器本身传参
  3. 向被装饰函数传参
  4. 实际案例:日志装饰器
  5. 缓存装饰器
  6. 同时处理装饰器和被装饰函数参数
  7. 高级案例:重试装饰器
  8. 参数传递示意图
  9. 关键要点

我来详细讲解 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)

关键要点

  1. 三层嵌套结构

    • 最外层:接收装饰器参数
    • 中间层:接收被装饰函数
    • 内层:接收被装饰函数的参数
  2. 参数优先级

    • 装饰器参数:在装饰时确定
    • 函数参数:在调用时传递
  3. 保持函数签名

    • 使用 @functools.wraps(func) 保留原函数信息
  4. 灵活设计

    • 可以组合多个装饰器
    • 支持默认参数
    • 考虑错误处理

通过这些案例,你可以根据实际需求灵活设计带参数的 Python 装饰器。

抱歉,评论功能暂时关闭!