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 请求日志记录
- 缓存结果优化性能
- 函数调用耗时统计
🧩 拓展练习(动手实践)
- 编写一个装饰器,在函数执行前后打印当前时间。
- 实现一个缓存装饰器,缓存函数调用结果以提升重复调用效率。
- 创建一个装饰器,限制函数只能被调用一次(防止重复执行)。
- 编写一个装饰器,捕获函数异常并输出错误日志。
- 设计一个装饰器,支持传入参数决定是否启用某项功能(如 debug 模式)。
📚 推荐阅读
- Python 官方文档 - Decorators
- 《流畅的 Python》第 7 章 - 装饰器与闭包
- 廖雪峰 Python 教程 - 装饰器
- 菜鸟教程 - Python 装饰器
- Real Python - Primer on Python Decorators
🧭 下一步建议
- 下一章学习内容:《Python3 模块与包管理》
- 掌握模块导入机制、相对导入、
__init__.py
文件的作用 - 学习
importlib
动态导入、sys.path
修改方法 - 探索标准库模块(如
os
,sys
,datetime
,json
等)的使用 - 结合装饰器与函数知识,尝试编写可复用性强的工具模块
如果你希望我为你提供:
- Python 装饰器速查表 PDF(含示例 + 执行流程图解)
- 更多实战项目练习题(如权限验证器、缓存系统、API 日志器等)
- 装饰器高级技巧详解(如类装饰器、带参装饰器、多层嵌套装饰器)
- 视频教学资源推荐(中文讲解)
欢迎随时告诉我 😊