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

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

admin6个月前 (03-19)Python219

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

理解装饰器的关键在于明白它本质上是一个"函数的包装器"。它接收一个函数作为输入,返回一个新的函数,这个新函数在调用原函数前后可以执行额外的逻辑。这种设计遵循了开放封闭原则——对扩展开放,对修改封闭。

让我们从一个最简单的装饰器开始。假设我们想给多个函数添加执行时间统计功能,传统做法是在每个函数内部添加计时代码,但这会导致代码重复。使用装饰器,我们可以将计时逻辑封装一次,然后应用到任意函数上:

python
import time
from functools import wraps

def timer_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()
        print(f"{func.__name__} 执行耗时:{end - start:.4f}秒")
        return result
    return wrapper

@timer_decorator
def calculate_sum(n):
    return sum(i * i for i in range(n))

@timer_decorator
def slow_operation():
    time.sleep(1)
    return "完成"

calculate_sum(1000000)
slow_operation()

这个示例展示了装饰器的基本结构:外层函数接收被装饰的函数,内层 wrapper 函数负责执行额外逻辑。使用@wraps 装饰器可以保留原函数的元信息,如函数名、文档字符串等,这在调试时非常重要。

实际开发中,我们经常需要带参数的装饰器。比如实现一个可配置的重试机制,当函数执行失败时自动重试指定次数:

python
import random
from functools import wraps

def retry(max_attempts=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            attempts = 0
            while attempts < max_attempts:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    attempts += 1
                    if attempts >= max_attempts:
                        raise
                    print(f"第{attempts}次重试,等待{delay}秒...")
                    time.sleep(delay)
        return wrapper
    return decorator

@retry(max_attempts=3, delay=0.5)
def unstable_api():
    if random.random() < 0.7:
        raise ConnectionError("网络波动")
    return "API 调用成功"

print(unstable_api())

带参数的装饰器需要三层嵌套:最外层接收装饰器参数,中间层接收被装饰函数,最内层是实际执行的 wrapper。这种模式在实现可配置的行为时非常有用。

缓存是另一个装饰器的经典应用场景。对于计算密集型或 IO 密集型函数,我们可以缓存之前的计算结果,避免重复执行:

python
from functools import wraps

def simple_cache(func):
    cache = {}
    
    @wraps(func)
    def wrapper(*args):
        if args in cache:
            print(f"从缓存命中:{args}")
            return cache[args]
        result = func(*args)
        cache[args] = result
        print(f"缓存新结果:{args}")
        return result
    return wrapper

@simple_cache
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))
print(fibonacci(10)) # 直接从缓存读取

这个简单的缓存装饰器展示了闭包的力量——cache 字典在 wrapper 函数外部定义,但在内部被引用,因此可以在多次函数调用之间保持状态。实际项目中,Python 标准库的 functools.lru_cache 提供了更完善的实现。

权限验证是 Web 开发中的常见需求。使用装饰器,我们可以将权限检查逻辑与业务逻辑分离,使代码更加清晰:

python
from functools import wraps

class User:
    def __init__(self, name, role):
        self.name = name
        self.role = role

current_user = None

def require_role(required_role):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if current_user is None:
                raise PermissionError("用户未登录")
            if current_user.role != required_role:
                raise PermissionError(f"需要{required_role}权限")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@require_role("admin")
def delete_user(user_id):
    return f"删除用户 {user_id}"

@require_role("user")
def view_profile():
    return f"查看 {current_user.name} 的个人资料"

current_user = User("张三", "admin")
print(delete_user(123))

最后一个实用场景是日志记录。在生产环境中,记录函数的输入输出对于排查问题至关重要:

python
import logging
from functools import wraps
from datetime import datetime

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def log_calls(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        logger.info(f"[{timestamp}] 调用 {func.__name__}")
        logger.info(f"参数:args={args}, kwargs={kwargs}")
        try:
            result = func(*args, **kwargs)
            logger.info(f"返回:{result}")
            return result
        except Exception as e:
            logger.error(f"异常:{e}")
            raise
    return wrapper

@log_calls
def divide(a, b):
    return a / b

divide(10, 2)

通过以上 5 个场景,我们可以看到装饰器的强大之处:它将横切关注点(如日志、缓存、权限)与核心业务逻辑分离,使代码更加模块化、可维护。掌握装饰器后,你可以编写出更加优雅和 Pythonic 的代码。

装饰器的学习曲线可能有些陡峭,但一旦理解其本质——函数的高阶应用和闭包的结合——就会发现它是 Python 中最优雅的特性之一。建议从简单的装饰器开始练习,逐步过渡到带参数和类装饰器,最终能够灵活运用这一强大工具。

相关文章

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

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

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

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

Python 装饰器实用指南:从入门到精通

装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。这个概念听起来有些抽象,但让我们通过一个具体的例子来理解它的实际价值。想象一下,你正在开发一个 Web 应用,需要记录每个函数的执行时间。如果...

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

装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。理解这一点是掌握装饰器的关键。让我们从最简单的例子开始,逐步深入到复杂的应用场景。首先,我们需要理解函数在 Python 中是一等公民。这意味...

Python装饰器实战:从零到精通的5个经典场景

Python装饰器(Decorator)是一个非常强大且优雅的语言特性,它允许我们在不修改原函数代码的情况下,为函数添加额外的功能。本文将通过5个实战场景,带你深入理解装饰器的原理和应用。 一、装饰...

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

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

发表评论

访客

看不清,换一张

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