Python3 装饰器

Python3 装饰器(Decorators)


🎯 学习目标

掌握 Python 装饰器 的基本概念、实现原理与实际应用场景。理解装饰器如何在不修改原函数代码的前提下,为其动态添加功能。能够在实际项目中灵活使用装饰器实现日志记录、权限控制、性能监控等高级功能。


🔑 核心重点

分类 内容
基本概念 装饰器本质是一个函数,用于包装另一个函数或类
实现方式 使用高阶函数、闭包结构实现;可嵌套多个装饰器
语法糖 使用 @decorator 语法简化装饰过程
应用场景 日志记录、权限验证、缓存机制、函数计时、输入校验等
注意事项 避免装饰器副作用;注意参数传递和返回值处理

📚 详细讲解

一、什么是装饰器?

装饰器是一种设计模式,允许你在不修改函数本身逻辑的情况下,为其添加额外行为。它本质上是一个接收函数作为参数并返回新函数的“高阶函数”。

✅ 示例:最简单的装饰器

def my_decorator(func):
    def wrapper():
        print("函数执行前的操作")
        func()
        print("函数执行后的操作")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

📌 输出:

函数执行前的操作
Hello!
函数执行后的操作

二、带参数的装饰器

当被装饰的函数有参数时,装饰器内部也要能够正确接收这些参数。

✅ 示例:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("装饰器前置操作")
        result = func(*args, **kwargs)
        print("装饰器后置操作")
        return result
    return wrapper

@my_decorator
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

三、装饰器本身带参数

有时候我们希望装饰器可以根据不同的参数来改变行为。

✅ 示例:带参数的装饰器

def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say(msg):
    print(msg)

say("Hi")

📌 输出:

Hi
Hi
Hi

四、多个装饰器叠加使用

可以为一个函数应用多个装饰器,它们将按从内到外的顺序依次执行。

✅ 示例:

def decorator1(func):
    def wrapper(*args, **kwargs):
        print("decorator1 前")
        result = func(*args, **kwargs)
        print("decorator1 后")
        return result
    return wrapper

def decorator2(func):
    def wrapper(*args, **kwargs):
        print("decorator2 前")
        result = func(*args, **kwargs)
        print("decorator2 后")
        return result
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello")

say_hello()

📌 输出顺序:

decorator1 前
decorator2 前
Hello
decorator2 后
decorator1 后

五、使用 functools.wraps 保留元数据

默认情况下,装饰器会覆盖原始函数的元信息(如 __name__, __doc__ 等)。我们可以使用 functools.wraps 来保留这些信息。

✅ 示例:

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("装饰器操作")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def greet(name):
    """向用户打招呼"""
    print(f"Hello, {name}!")

print(greet.__name__)   # 输出 greet
print(greet.__doc__)    # 输出 向用户打招呼

六、类作为装饰器

除了函数,我们也可以使用类来定义装饰器,通常通过重写 __call__ 方法。

✅ 示例:

class MyDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("装饰器前置操作")
        result = self.func(*args, **kwargs)
        print("装饰器后置操作")
        return result

@MyDecorator
def say_hello():
    print("Hello!")

say_hello()

⚠️ 注意事项

  • 装饰器不应影响被装饰函数的正常逻辑(无副作用)
  • 尽量使用 functools.wraps 保留函数元信息
  • 不要过度嵌套装饰器,避免调试困难
  • 多个装饰器叠加时注意执行顺序(从下往上)
  • 装饰器适用于通用增强逻辑,不适合复杂业务逻辑

🧪 实际案例分析

📌 场景:登录权限验证系统

模拟一个 Web 框架中的登录验证逻辑。

def login_required(func):
    @wraps(func)
    def wrapper(user, *args, **kwargs):
        if user.get("is_authenticated"):
            return func(user, *args, **kwargs)
        else:
            print("访问被拒绝:用户未登录")
            return None
    return wrapper

@login_required
def access_profile(user):
    print(f"欢迎访问 {user['name']} 的个人资料")

# 测试用户
user1 = {"name": "Alice", "is_authenticated": True}
user2 = {"name": "Bob", "is_authenticated": False}

access_profile(user1)  # 成功访问
access_profile(user2)  # 被拒绝

📌 输出:

欢迎访问 Alice 的个人资料
访问被拒绝:用户未登录

📌 应用

  • 接口权限控制
  • API 请求日志记录
  • 缓存结果优化性能
  • 函数调用耗时统计

🧩 拓展练习(动手实践)

  1. 编写一个装饰器,在函数执行前后打印当前时间。
  2. 实现一个缓存装饰器,缓存函数调用结果以提升重复调用效率。
  3. 创建一个装饰器,限制函数只能被调用一次(防止重复执行)。
  4. 编写一个装饰器,捕获函数异常并输出错误日志。
  5. 设计一个装饰器,支持传入参数决定是否启用某项功能(如 debug 模式)。

📚 推荐阅读


🧭 下一步建议

  • 下一章学习内容:《Python3 模块与包管理》
  • 掌握模块导入机制、相对导入、__init__.py 文件的作用
  • 学习 importlib 动态导入、sys.path 修改方法
  • 探索标准库模块(如 os, sys, datetime, json 等)的使用
  • 结合装饰器与函数知识,尝试编写可复用性强的工具模块

如果你希望我为你提供:

  • Python 装饰器速查表 PDF(含示例 + 执行流程图解)
  • 更多实战项目练习题(如权限验证器、缓存系统、API 日志器等)
  • 装饰器高级技巧详解(如类装饰器、带参装饰器、多层嵌套装饰器)
  • 视频教学资源推荐(中文讲解)

欢迎随时告诉我 😊

posted @ 2025-05-28 23:38  红尘过客2022  阅读(51)  评论(0)    收藏  举报