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

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

admin2周前 (03-22)Python22

装饰器本质上是一个接受函数作为参数,并返回一个新函数的函数。这种设计模式源自函数式编程,在 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 教程] Matplotlib 数据可视化教程

Matplotlib 数据可视化教程 Matplotlib 是 Python 最常用的绘图库。本文介绍常用图表的绘制方法。 一、基础设置 import matplotlib.pyplot as pl...

Python 装饰器实用技巧:从入门到精通

装饰器是 Python 最强大的特性之一,但也是很多开发者感到困惑的概念。简单来说,装饰器是一个函数,它接受另一个函数作为输入,并返回一个新的函数。使用装饰器,你可以在不修改原函数代码的情况下,为其添...

Python 上下文管理器实战:从 with 语句到自定义资源管理

在 Python 编程中,上下文管理器(Context Manager)是一个强大但常被低估的特性。当你使用 open() 函数读取文件时,那个熟悉的 with 语句背后,正是上下文管理器在默默工作。...

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

装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。理解这一点是掌握装饰器的关键。想象一下,你有一个函数,你想在它执行前后添加一些额外的逻辑,比如日志记录、性能测试、权限验证等。装饰器就是为这种...

Python 装饰器实战:从入门到精通

装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。理解这一点是掌握装饰器的关键。当你看到@decorator 语法时,Python 实际上是在执行 func = decorator(func)...

Python 装饰器从入门到实战:5 个实用场景详解

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

发表评论

访客

看不清,换一张

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