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

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

admin4周前 (03-22)Python28

装饰器本质上是一个接受函数作为参数,并返回一个新函数的函数。这种设计模式源自函数式编程,在 Python 中通过 @ 语法得到优雅的体现。理解装饰器的核心在于掌握闭包的概念——内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。

让我们从一个基础的装饰器开始。下面的示例展示了一个计时装饰器,它可以测量函数执行时间:

import time\nimport functools\n\ndef timer(func):\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n        start = time.perf_counter()\n        result = func(*args, **kwargs)\n        end = time.perf_counter()\n        print(f"{func.__name__} 执行耗时: {end - start:.4f} 秒")\n        return result\n    return wrapper\n\n@timer\ndef fibonacci(n):\n    if n <= 1:\n        return n\n    return fibonacci(n-1)   fibonacci(n-2)

在上面的代码中,functools.wraps 是一个关键工具。它复制了原始函数的元信息(如 __name__、__doc__),这对于调试和文档生成非常重要。没有它,装饰后的函数名称会变成 'wrapper',这会混淆日志和错误追踪。

装饰器的真正威力体现在它能够组合使用。你可以将多个装饰器堆叠在一起,每个装饰器负责一个特定的关注点。这种组合方式实现了关注点分离,使代码更加模块化。例如,我们可以同时使用计时和日志装饰器:

def logger(func):\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n        print(f"[调用] {func.__name__} 参数: args={args}, kwargs={kwargs}")\n        result = func(*args, **kwargs)\n        print(f"[返回] {func.__name__} 结果: {result}")\n        return result\n    return wrapper\n\n@logger\n@timer\ndef data_processing(data):\n    time.sleep(0.1)  # 模拟处理\n    return [x * 2 for x in data]

类装饰器提供了另一种实现方式。当你需要维护装饰器的状态,或者想要更结构化的代码组织时,类装饰器是理想的选择。类装饰器通过实现 __call__ 方法来使实例可调用:

class CountCalls:\n    def __init__(self, func):\n        self.func = func\n        self.count = 0\n        functools.update_wrapper(self, func)\n\n    def __call__(self, *args, **kwargs):\n        self.count  = 1\n        print(f"{self.func.__name__} 被调用第 {self.count} 次")\n        return self.func(*args, **kwargs)\n\n@CountCalls\ndef calculate_total(prices):\n    return sum(prices)

带参数的装饰器是更高级的应用场景。当你想要根据不同的配置来定制装饰器的行为时,这种模式非常有用。实现带参数的装饰器需要额外的函数层嵌套:

def repeat(times):\n    def decorator(func):\n        @functools.wraps(func)\n        def wrapper(*args, **kwargs):\n            results = []\n            for _ in range(times):\n                results.append(func(*args, **kwargs))\n            return results\n        return wrapper\n    return decorator\n\n@repeat(times=3)\ndef random_number():\n    import random\n    return random.randint(1, 100)

在实际应用中,装饰器常用于缓存昂贵的计算结果。下面的 memoize 装饰器实现了简单的记忆化功能,可以显著提升递归算法的性能:

class memoize:\n    def __init__(self, func):\n        self.func = func\n        self.cache = {}\n        functools.update_wrapper(self, func)\n\n    def __call__(self, *args):\n        if args not in self.cache:\n            self.cache[args] = self.func(*args)\n        return self.cache[args]\n\n@memoize\ndef optimized_fibonacci(n):\n    if n <= 1:\n        return n\n    return optimized_fibonacci(n-1)   optimized_fibonacci(n-2)

装饰器还可以用于实现重试机制,这在网络请求和外部 API 視用中特别有用。下面的 retry 装饰器会在函数失败时自动重试指定次数:

def retry(max_attempts=3, delay=1):\n    def decorator(func):\n        @functools.wraps(func)\n        def wrapper(*args, **kwargs):\n            for attempt in range(max_attempts):\n                try:\n                    return func(*args, **kwargs)\n                except Exception as e:\n                    if attempt == max_attempts - 1:\n                        raise\n                    print(f"第 {attempt   1} 次尝试失败: {e}")\n                    time.sleep(delay)\n        return wrapper\n    return decorator\n\n@retry(max_attempts=3, delay=1)\ndef fetch_data():\n    import random\n    if random.random() > 0.7:\n        raise ConnectionError("网络连接失败")\n    return {"status": "success", "data": [1, 2, 3]}

最后,装饰器还可以用于权限验证和访问控制。这种模式在 Web 开发中非常常见:

def require_role(required_role):\n    def decorator(func):\n        @functools.wraps(func)\n        def wrapper(*args, **kwargs):\n            user = kwargs.get('user') or args[0] if args else None\n            if not user or user.get('role') != required_role:\n                raise PermissionError(f"需要 {required_role} 权限")\n            return func(*args, **kwargs)\n        return wrapper\n    return decorator\n\n@require_role('admin')\ndef delete_user(user_id, user=None):\n    print(f"删除用户 {user_id}")

掌握装饰器的高级用法,将使你的代码更加优雅和可维护。通过合理使用装饰器,你可以将横切关注点(如日志、缓存、验证)从业务逻辑中分离出来,实现更加清晰的代码结构。在日常开发中,多思考哪些功能可以抽取为装饰器,这将是提升代码质量的有效途径。

相关文章

[Python 教程] OpenCV 实战:图像与视频文件处理

OpenCV 实战:图像与视频文件处理本文详细介绍如何使用 OpenCV 处理图像和视频文件,包括读取、显示、保存等操作。一、图像文件操作1.1 读取图像import cv2 #&nb...

Python 装饰器的高级应用与实战技巧

装饰器本质上是接受函数作为参数并返回新函数的高阶函数。理解这一点是掌握装饰器的关键。让我们从基础开始,逐步深入到高级应用。首先,我们需要理解函数在 Python 中是一等公民。这意味着函数可以像其他对...

Python 装饰器实战:从基础到高级应用的完整指南

装饰器是 Python 中最优雅也最强大的特性之一。它允许你在不修改原函数代码的前提下,动态地添加功能。本文将带你从装饰器的基础概念出发,逐步掌握其在实际开发中的高级应用技巧。许多初学者对装饰器感到困...

Python 装饰器完全指南:从原理到实战的 5 个核心场景

装饰器(Decorator)是 Python 中最具魅力的特性之一。它允许我们在不修改原函数代码的前提下,动态地添加功能。但很多开发者对装饰器的理解仅停留在在函数上面加个@符号的层面。今天,我们将从底...

Python 上下文管理器的实战应用与原理深度解析

Python 上下文管理器的实战应用与原理深度解析 概述 上下文管理器是 Python 中一个优雅而强大的特性,通过 with 语句实现资源的自动管理。本文将从原理到实践,深入讲解如何创建自定义上下...

Python 上下文管理器实战指南:优雅处理资源的艺术

# Python 上下文管理器实战指南:优雅处理资源的艺术 在 Python 编程中,资源的获取与释放是一个永恒的主题。文件操作、数据库连接、网络请求、锁的获取...这些场景都遵循相同的模式:打开资...

发表评论

访客

看不清,换一张

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