第77集:装饰器基础
学习目标
- 理解装饰器的概念和作用
- 掌握装饰器的基本语法
- 学会创建简单的装饰器
- 理解装饰器的执行流程
- 掌握带参数的装饰器
- 了解装饰器的应用场景
什么是装饰器
装饰器(Decorator)是Python中一种特殊的语法,用于在不修改原函数代码的情况下,为函数添加额外的功能。装饰器本质上是一个接受函数作为参数并返回新函数的函数。
装饰器的特点
- 不修改原函数代码
- 不改变原函数调用方式
- 可以添加额外功能
- 可以组合使用多个装饰器
- 支持带参数的装饰器
基本语法
语法结构
@decorator
def function():
pass等价形式
def function():
pass
function = decorator(function)基本示例
示例1:简单装饰器
def my_decorator(func):
"""简单装饰器"""
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
# 调用函数
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后示例2:装饰器执行流程
def decorator(func):
print("1. 装饰器被调用")
def wrapper():
print("3. wrapper函数被调用")
func()
print("5. 函数执行完成")
print("2. wrapper函数被创建")
return wrapper
@decorator
def my_function():
print("4. 原函数执行")
print("装饰器应用完成")
my_function()示例3:保留原函数信息
def my_decorator(func):
"""保留原函数信息的装饰器"""
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
return wrapper
@my_decorator
def add(a, b):
"""加法函数"""
return a + b
print(add.__name__) # add
print(add.__doc__) # 加法函数常用装饰器模式
模式1:计时装饰器
import time
def timer(func):
"""计时装饰器"""
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} 执行时间: {end_time - start_time:.4f}秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
print("函数执行中...")
slow_function()模式2:日志装饰器
def logger(func):
"""日志装饰器"""
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
print(f"参数: args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"返回值: {result}")
return result
return wrapper
@logger
def add(a, b):
return a + b
add(3, 5)模式3:缓存装饰器
def memoize(func):
"""缓存装饰器"""
cache = {}
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def fibonacci(n):
"""斐波那契数列"""
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))带参数的装饰器
示例4:带参数的装饰器
def repeat(times):
"""重复执行装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
say_hello()
# 输出3次Hello!示例5:带参数的日志装饰器
def log(prefix=""):
"""带前缀的日志装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{prefix} 调用函数: {func.__name__}")
result = func(*args, **kwargs)
print(f"{prefix} 返回值: {result}")
return result
return wrapper
return decorator
@log("DEBUG:")
def add(a, b):
return a + b
add(3, 5)多个装饰器
示例6:多个装饰器组合
def decorator1(func):
def wrapper():
print("装饰器1 - 前")
func()
print("装饰器1 - 后")
return wrapper
def decorator2(func):
def wrapper():
print("装饰器2 - 前")
func()
print("装饰器2 - 后")
return wrapper
@decorator1
@decorator2
def my_function():
print("原函数")
my_function()
# 输出:
# 装饰器1 - 前
# 装饰器2 - 前
# 原函数
# 装饰器2 - 后
# 装饰器1 - 后装饰器的应用场景
场景1:权限验证
def login_required(func):
"""登录验证装饰器"""
def wrapper(*args, **kwargs):
if not is_logged_in():
raise PermissionError("需要登录")
return func(*args, **kwargs)
return wrapper
@login_required
def delete_user(user_id):
print(f"删除用户: {user_id}")
def is_logged_in():
return True
delete_user(123)场景2:输入验证
def validate_positive(func):
"""验证参数为正数"""
def wrapper(*args, **kwargs):
for arg in args:
if not isinstance(arg, (int, float)) or arg <= 0:
raise ValueError("参数必须为正数")
return func(*args, **kwargs)
return wrapper
@validate_positive
def calculate_area(length, width):
return length * width
print(calculate_area(5, 3))场景3:性能监控
def performance_monitor(func):
"""性能监控装饰器"""
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行时间: {end-start:.4f}秒")
return result
return wrapper
@performance_monitor
def process_data(data):
total = sum(data)
return total
process_data(range(1000000))functools.wraps
使用functools.wraps
from functools import wraps
def my_decorator(func):
"""使用wraps保留原函数信息"""
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def add(a, b):
"""加法函数"""
return a + b
print(add.__name__) # add
print(add.__doc__) # 加法函数为什么使用functools.wraps
# 不使用wraps
def decorator_without_wraps(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator_without_wraps
def func1():
"""函数1"""
pass
print(func1.__name__) # wrapper
print(func1.__doc__) # None
# 使用wraps
def decorator_with_wraps(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator_with_wraps
def func2():
"""函数2"""
pass
print(func2.__name__) # func2
print(func2.__doc__) # 函数2装饰器的限制
限制1:修改原函数签名
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def add(a, b):
return a + b
# 装饰器后,函数签名可能改变
import inspect
print(inspect.signature(add)) # (*args, **kwargs)限制2:调试困难
# 装饰器可能使调试变得困难
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def my_function():
pass
# 堆栈跟踪可能显示wrapper而不是my_function最佳实践
实践1:使用functools.wraps
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper实践2:保持装饰器简单
# 推荐:简单的装饰器
def simple_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
# 不推荐:复杂的装饰器
def complex_decorator(func):
def wrapper(*args, **kwargs):
# 大量逻辑
pass
return wrapper实践3:使用类装饰器处理复杂逻辑
class MyDecorator:
"""类装饰器"""
def __init__(self, func):
self.func = func
wraps(func)(self)
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
@MyDecorator
def my_function():
pass实践4:文档化装饰器
def my_decorator(func):
"""
装饰器文档
Args:
func: 被装饰的函数
Returns:
包装后的函数
"""
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper常见错误
错误1:忘记返回wrapper函数
# 错误:忘记返回wrapper函数
def bad_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
# 忘记return wrapper
# 正确:返回wrapper函数
def good_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper错误2:忘记使用*args和**kwargs
# 错误:不接受参数
def bad_decorator(func):
def wrapper():
return func()
return wrapper
# 正确:接受任意参数
def good_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper错误3:忘记调用原函数
# 错误:忘记调用原函数
def bad_decorator(func):
def wrapper(*args, **kwargs):
# 忘记调用func()
pass
return wrapper
# 正确:调用原函数
def good_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper总结
装饰器是Python中强大的工具,具有以下特点:
核心概念
- 装饰器是一个接受函数并返回新函数的函数
- 使用@语法糖简化装饰器的应用
- 可以在不修改原函数代码的情况下添加功能
优势
- 代码复用
- 关注点分离
- 提高代码可读性
- 易于维护
应用场景
- 日志记录
- 性能监控
- 权限验证
- 缓存
- 输入验证
掌握装饰器将帮助你编写更优雅、更可维护的Python代码。装饰器是Python中重要的概念,理解它的工作原理对于编写高质量的Python程序至关重要。