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

Python 装饰器的 5 个实用场景:从入门到精通

admin2个月前 (03-19)Python89

装饰器(Decorator)是 Python 中的"函数包装器",它允许我们在不修改原函数代码的前提下,动态地添加功能。很多初学者学完 @decorator 语法后就止步不前,但实际上装饰器在实际工程中的应用远不止简单的日志打印。今天,我将分享 5 个我在实际项目中经常使用的装饰器模式,每个都能解决一类具体问题。

场景一:性能计时装饰器

在优化代码性能时,我们首先需要知道哪些函数是瓶颈。这个装饰器可以自动记录函数的执行时间:

import time
import functools
from typing import Callable, Any

def timer(func: Callable) -> Callable:
    """记录函数执行时间的装饰器"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs) -> Any:
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        elapsed = end_time - start_time
        print(f"⏱️  {func.__name__} 执行时间: {elapsed:.4f} 秒")
        return result
    return wrapper

这个装饰器的关键在于使用 time.perf_counter()而不是 time.time()而是前者提供更高精度的性能计时。同时,@functools.wraps保留了原函数的元数据,这对调试和文档生成非常重要。

场景二:智能缓存装饰器

对于计算密集型且结果可复用的函数,缓存可以带来显著的性能提升。下面是一个支持过期时间的缓存装饰器:

import functools
from typing import Callable, Any, Dict
from datetime import datetime, timedelta

def cached(timeout_seconds: int = 300):
    """带过期时间的缓存装饰器"""
    cache: Dict[str, tuple] = {}
    
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            key = f"{func.__name__}:{args}:{sorted(kwargs.items())}"
            if key in cache:
                result, timestamp = cache[key]
                if datetime.now() - timestamp < timedelta(seconds=timeout_seconds):
                    return result
            result = func(*args, **kwargs)
            cache[key] = (result, datetime.now())
            return result
        return wrapper
    return decorator

这个装饰器的亮点在于支持缓存过期时间,避免了无限期缓存导致的内存问题。

场景三:权限验证装饰器

在 Web 应用或 API 服务中,权限验证是常见需求。这个装饰器可以统一处理权限检查逻辑:

from dataclasses import dataclass
from typing import Callable, Any, List, Optional

@dataclass
class User:
    username: str
    roles: List[str]
    is_active: bool = True

class PermissionDenied(Exception):
    pass

def require_auth(func: Callable) -> Callable:
    @functools.wraps(func)
    def wrapper(user: Optional[User] = None, *args, **kwargs) -> Any:
        if user is None or not user.is_active:
            raise PermissionDenied("用户未登录")
        return func(user, *args, **kwargs)
    return wrapper

def require_roles(*allowed_roles: str):
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(user: User, *args, **kwargs) -> Any:
            if not any(role in user.roles for role in allowed_roles):
                raise PermissionDenied("权限不足")
            return func(user, *args, **kwargs)
        return wrapper
    return decorator

这个装饰器采用了装饰器工厂模式,可以灵活组合多个权限要求。

场景四:自动重试装饰器

网络请求、数据库操作等容易失败的场景,自动重试可以显著提高系统的健壮性:

import functools
import time
import random
from typing import Callable, Any, Tuple, Type

def retry(
    max_attempts: int = 3,
    delay: float = 1.0,
    backoff: float = 2.0,
    exceptions: Tuple[Type[Exception], ...] = (Exception,)
):
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            current_delay = delay
            for attempt in range(1, max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    if attempt < max_attempts:
                        time.sleep(current_delay)
                        current_delay *= backoff
            raise e
        return wrapper
    return decorator

这个重试装饰器实现了指数退避算法,每次重试的等待时间会成倍增长。

场景五:结构化日志装饰器

在生产环境中,结构化的日志对于问题排查至关重要。这个装饰器可以自动记录函数的输入输出:

import functools
import logging
from typing import Callable, Any, Optional

logger = logging.getLogger(__name__)

def logged(
    level: int = logging.INFO,
    mask_fields: Optional[list] = None
):
    mask_fields = mask_fields or ["password", "token"]
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            logger.info(f"调用 {func.__name__}")
            try:
                result = func(*args, **kwargs)
                logger.info(f"完成 {func.__name__}")
                return result
            except Exception as e:
                logger.error(f"异常 {func.__name__}: {e}")
                raise
        return wrapper
    return decorator

这个日志装饰器的特色在于支持敏感字段脱敏,避免密码等敏感信息泄露。

总结

通过以上 5 个场景,我们可以看到装饰器的强大之处:单一职责、保留元数据、参数化支持、异常处理和可测试性。装饰器是 Python 优雅性的体现之一,掌握这些模式后,你的代码将变得更加模块化和可维护。

相关文章

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

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

深入理解 Python 上下文管理器:从基础到高级应用

Python 的 with 语句和上下文管理器是每个开发者都应该掌握的高级技巧,但很多初学者对它的理解仅仅停留在文件操作层面。本文将深入讲解上下文管理器的原理、多种实现方式,以及在实际开发中的高级应用...

深入理解 Python 装饰器:从基础到高级的完整指南

什么是装饰器?装饰器本质上是一个 Python 函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。装饰器的返回值通常也是一个函数对象。这种设计模式遵循了"开放封闭原则"——对扩展开放,...

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

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

Python 类型提示实战指南:让代码更健壮

类型提示并不是强制执行的类型系统,而是一种可选的代码文档化工具。它通过注解函数参数和返回值的类型,帮助开发者更清晰地表达意图,同时让 IDE 和类型检查器(如 mypy)能够提前发现潜在的类型错误。...

Python 数据处理三部曲:从清洗到可视化的实战指南

在现代数据驱动的工作场景中,无论是处理实验数据、分析用户行为,还是监控业务指标,高效的数据处理能力都是不可或缺的。Python 提供了一套完整的数据处理工具链,其中 NumPy、Pandas 和 Ma...

发表评论

访客

看不清,换一张

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