当前位置:首页 > Python > 正文内容

Python 装饰器进阶:带参数装饰器与类装饰器实战

admin2个月前 (03-22)Python80

装饰器(Decorator)是 Python 中最优雅的特性之一,它允许我们在不修改原函数代码的情况下,为函数添加额外功能。上一篇我们学习了基础装饰器,今天将深入探讨两个进阶主题:带参数的装饰器和类装饰器。

## 带参数的装饰器

基础装饰器只能接收被装饰的函数,但有时我们希望装饰器也能接收参数。例如,创建一个可配置的重试装饰器:

def retry(max_attempts=3, delay=1):\n    \"\"\"带参数的装饰器工厂函数\"\"\"\n    import time\n    \n    def decorator(func):\n        def wrapper(*args, **kwargs):\n            last_exception = None\n            for attempt in range(1, max_attempts   1):\n                try:\n                    return func(*args, **kwargs)\n                except Exception as e:\n                    last_exception = e\n                    if attempt < max_attempts:\n                        print(f\"第 {attempt} 次尝试失败, {delay}秒后重试...\")\n                        time.sleep(delay)\n            raise last_exception\n        return wrapper\n    return decorator\n

使用带参数装饰器时,括号是必需的:

@retry(max_attempts=5, delay=2)\ndef fetch_data(url):\n    import random\n    if random.random() < 0.7:\n        raise ConnectionError(\"网络连接失败\")\n    return \"数据获取成功\"\n\n# 调用函数\nprint(fetch_data(\"https://api.example.com\"))\n

## 类装饰器

装饰器不仅可以是函数,还可以是类。类装饰器使用 __call__ 方法来实现装饰功能:

class Timer:\n    \"\"\"类装饰器,用于测量函数执行时间\"\"\"\n    \n    def __init__(self, func):\n        self.func = func\n        \n    def __call__(self, *args, **kwargs):\n        import time\n        start_time = time.time()\n        result = self.func(*args, **kwargs)\n        end_time = time.time()\n        print(f\"{self.func.__name__} 执行时间: {end_time - start_time:.4f}秒\")\n        return result\n

使用类装饰器时,不需要括号:

@Timer\ndef fibonacci(n):\n    if n <= 1:\n        return n\n    return fibonacci(n-1)   fibonacci(n-2)\n\nprint(fibonacci(30))\n

## 带参数的类装饰器

如果需要带参数的类装饰器,需要一个两层嵌套结构:

class RateLimit:\n    \"\"\"带参数的类装饰器,实现调用频率限制\"\"\"\n    \n    def __init__(self, calls_per_second=1):\n        self.calls_per_second = calls_per_second\n        self.last_call_time = 0\n        \n    def __call__(self, func):\n        def wrapper(*args, **kwargs):\n            import time\n            current_time = time.time()\n            time_since_last_call = current_time - self.last_call_time\n            \n            if time_since_last_call < (1.0 / self.calls_per_second):\n                sleep_time = (1.0 / self.calls_per_second) - time_since_last_call\n                print(f\"达到频率限制,等待 {sleep_time:.2f}秒...\")\n                time.sleep(sleep_time)\n                \n            self.last_call_time = time.time()\n            return func(*args, **kwargs)\n        return wrapper\n

使用带参数的类装饰器:

@RateLimit(calls_per_second=2)\ndef api_request(request_id):\n    print(f\"处理请求 #{request_id}\")\n    \nfor i in range(5):\n    api_request(i 1)\n

## 装饰器叠加

多个装饰器可以叠加使用,执行顺序是从内到外(从下到上):

@retry(max_attempts=3)\n@Timer\ndef process_file(filepath):\n    import random\n    if random.random() < 0.5:\n        raise IOError(\"文件读取错误\")\n    print(f\"处理文件: {filepath}\")\n    return \"处理完成\"\n\nprocess_file(\"data.txt\")\n

## 实战案例:缓存装饰器

下面是一个实用的缓存装饰器,可以缓存函数结果避免重复计算:

def cache(max_size=128):\n    \"\"\"带参数的缓存装饰器\"\"\"\n    from functools import lru_cache\n    \n    def decorator(func):\n        return lru_cache(maxsize=max_size)(func)\n    return decorator\n\n@cache(max_size=64)\ndef expensive_computation(n):\n    print(f\"计算 {n} 的平方...\")\n    return n ** 2\n\n# 第一次调用会执行计算\nprint(expensive_computation(5))\n\n# 第二次调用从缓存读取\nprint(expensive_computation(5))\n

## 保留原函数元数据

装饰器会覆盖原函数的 __name____doc__ 等属性。使用 functools.wraps 可以保留这些元数据:

from functools import wraps\n\ndef log_function_call(func):\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        print(f\"调用函数: {func.__name__}\")\n        return func(*args, **kwargs)\n    return wrapper\n\n@log_function_call\ndef calculate_area(radius):\n    \"\"\"计算圆的面积\"\"\"\n    return 3.14159 * radius ** 2\n\nprint(calculate_area.__name__)  # 输出: calculate_area\nprint(calculate_area.__doc__)   # 输出: 计算圆的面积\n

## 总结

带参数装饰器通过"装饰器工厂函数"模式实现,需要三层嵌套结构。类装饰器使用 __call__ 魔术方法,更面向对象。两者都可以与基础装饰器自由组合,创造出强大的功能。

掌握这些进阶技巧后,你可以编写更灵活、更可复用的装饰器,为代码添加日志、缓存、权限验证、性能监控等功能,而无需修改业务逻辑代码。

相关文章

[Python 教程] OpenCV-Python 入门:图像处理基础详解

OpenCV-Python 入门:图像处理基础详解OpenCV 是一个跨平台计算机视觉库,轻量级且高效,支持 Python 接口。本文将系统介绍 OpenCV 的核心概念和基础操作。一、OpenCV...

Python 装饰器:从入门到实战的完整指南

装饰器(Decorator)是 Python中一种优雅的设计模式,它允许我们在不修改原函数代码的前提下,动态地添加功能。想象一下,你有一个已经写好的函数,现在需要为它添加日志记录、性能监控、权限验证等...

Python 生成器进阶:理解 yield 与构建高效迭代器

在 Python 开发中,我们经常需要处理大量数据或流式数据,如果一次性将所有数据加载到内存中,不仅会占用大量内存空间,还可能导致程序运行缓慢甚至崩溃。生成器(Generator)正是解决这个问题的利...

Python 装饰器:从原理到实战应用,打造优雅代码

在 Python 编程中,装饰器(Decorator)是一个经常被提及但又容易让初学者困惑的概念。简单来说,装饰器是一种设计模式,它允许我们在不修改原始函数代码的情况下,为函数添加额外的功能。这种"包...

Python 装饰器实战:从原理到高级应用

在 Python 开发中,我们经常需要在函数执行前后添加额外的逻辑,比如日志记录、性能计时、权限验证等。如果直接修改函数内部代码,会导致代码重复和耦合。装饰器正是为了解决这个问题而生。什么是装饰器?装...

Python 装饰器的高级用法:从基础到实战

装饰器(Decorator)是 Python 中最优雅和强大的特性之一。在日常开发中,我们经常使用 @staticmethod、@property 这样的内置装饰器,但你是否真正理解装饰器背后的工作原...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。