Python装饰器详解:原理、用法与实战案例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

什么是Python装饰器

如果你写过Python超过一周,你一定见过函数上方那个@符号。这就是装饰器——一个强大且易用的编程工具。

Python装饰器允许你将一个函数"包裹"在另一个函数中。它们可以在不修改原函数代码的情况下,改变或扩展函数的行为。装饰器被广泛应用于Flask、Django、FastAPI、pytest,甚至Python标准库中。

装饰器的工作原理

装饰器基础

装饰器本质上是一个函数,它接收另一个函数作为参数,并返回一个新的函数或修改后的原函数。

def decorator(func):
    def wrapper():
        print("调用前")
        func()
        print("调用后")
    return wrapper

@decorator
def say_hello():
    print("你好!")

say_hello()

执行结果:

调用前
你好!
调用后

@decorator 实际上是以下写法的语法糖:

say_hello = decorator(say_hello)

装饰器的内部机制

要理解Python装饰器,需要掌握几个关键概念:

  • 在Python中,函数是一等公民(first-class objects)
  • 函数可以作为参数传递给其他函数
  • 函数内部可以定义其他函数
  • 闭包(closure)机制的存在

通用装饰器模板

最简装饰器模板如下:

def decorator(func):
    def wrapper(*args, **kwargs):
        # 函数执行前的操作
        result = func(*args, **kwargs)
        # 函数执行后的操作
        return result
    return wrapper

装饰器实战案例

计时装饰器

import time

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

@timing
def slow_func():
    time.sleep(1)
    return "操作完成"

slow_func()

这个装饰器非常适合用于函数性能分析和代码优化。

权限验证装饰器

def require_admin(func):
    def wrapper(user, *args, **kwargs):
        if user != "admin":
            raise PermissionError("访问被拒绝")
        return func(user, *args, **kwargs)
    return wrapper

@require_admin
def delete_database(user):
    print("数据库已删除!")
    return True

delete_database("admin")  # 成功执行

这种装饰器通过控制对关键函数的访问,有效保障了应用安全。

日志记录装饰器

import logging
from functools import wraps

def log_calls(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        logging.info(f"调用函数 {func.__name__},参数为 {args}, {kwargs}")
        try:
            result = func(*args, **kwargs)
            logging.info(f"函数 {func.__name__} 执行成功")
            return result
        except Exception as e:
            logging.error(f"函数 {func.__name__} 出错:{e}")
            raise
    return wrapper

带参数的装饰器

创建装饰器工厂

当装饰器需要接收参数时,需要创建一个装饰器工厂:

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            results = []                

博客

书籍推荐