Appearance
Python 装饰器
装饰器是 Python 中一种强大的功能,用于修改函数或类的行为。本章节将详细介绍 Python 中的装饰器概念、实现原理和使用方法。
基本概念
装饰器是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器的作用是在不修改原函数代码的情况下,为函数添加额外的功能。
装饰器的语法使用 @ 符号,放在函数定义的上方。
基本语法
python
@decorator_function
def original_function():
# 函数体这相当于:
python
def original_function():
# 函数体
original_function = decorator_function(original_function)简单装饰器示例
第一个装饰器
python
# 简单装饰器示例
def my_decorator(func):
def wrapper():
print("在函数调用之前")
func()
print("在函数调用之后")
return wrapper
@my_decorator
def say_hello():
print("Hello, World!")
# 调用函数
say_hello()输出:
在函数调用之前
Hello, World!
在函数调用之后带参数的函数装饰器
python
# 带参数的函数装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print("在函数调用之前")
result = func(*args, **kwargs)
print("在函数调用之后")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
# 调用函数
result = add(3, 5)
print(f"结果:{result}")输出:
在函数调用之前
在函数调用之后
结果:8带参数的装饰器
装饰器本身也可以接受参数。
python
# 带参数的装饰器
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(n):
print(f"第 {i+1} 次调用")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello, World!")
# 调用函数
say_hello()输出:
第 1 次调用
Hello, World!
第 2 次调用
Hello, World!
第 3 次调用
Hello, World!装饰器的工作原理
装饰器的工作原理可以分为以下几个步骤:
- 定义一个装饰器函数,它接受一个函数作为参数。
- 在装饰器函数内部定义一个包装函数(wrapper),用于添加额外的功能。
- 包装函数调用原函数,并返回其结果。
- 装饰器函数返回包装函数。
- 使用
@语法将装饰器应用到目标函数上。
示例解析
python
# 装饰器的工作原理解析
def my_decorator(func):
print(f"装饰器被应用到函数 {func.__name__}")
def wrapper(*args, **kwargs):
print(f"调用函数 {func.__name__} 之前")
result = func(*args, **kwargs)
print(f"调用函数 {func.__name__} 之后")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
return f"Hello, {name}!"
print("\n调用函数之前")
result = say_hello("Alice")
print(f"函数返回值:{result}")输出:
装饰器被应用到函数 say_hello
调用函数之前
调用函数 say_hello 之前
Hello, Alice!
调用函数 say_hello 之后
函数返回值:Hello, Alice!保留函数元数据
当使用装饰器时,原函数的元数据(如函数名、文档字符串等)会丢失,因为装饰器返回的是包装函数。为了保留原函数的元数据,我们可以使用 functools.wraps 装饰器。
示例
python
# 保留函数元数据
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
"""包装函数的文档字符串"""
print("在函数调用之前")
result = func(*args, **kwargs)
print("在函数调用之后")
return result
return wrapper
@my_decorator
def say_hello():
"""打印问候语"""
print("Hello, World!")
# 查看函数元数据
print(f"函数名:{say_hello.__name__}")
print(f"文档字符串:{say_hello.__doc__}")
print(f"模块名:{say_hello.__module__}")
# 调用函数
say_hello()输出:
函数名:say_hello
文档字符串:打印问候语
模块名:__main__
在函数调用之前
Hello, World!
在函数调用之后不使用 functools.wraps 的情况
python
# 不使用 functools.wraps 的情况
def my_decorator(func):
def wrapper(*args, **kwargs):
"""包装函数的文档字符串"""
print("在函数调用之前")
result = func(*args, **kwargs)
print("在函数调用之后")
return result
return wrapper
@my_decorator
def say_hello():
"""打印问候语"""
print("Hello, World!")
# 查看函数元数据
print(f"函数名:{say_hello.__name__}")
print(f"文档字符串:{say_hello.__doc__}")
print(f"模块名:{say_hello.__module__}")
# 调用函数
say_hello()输出:
函数名:wrapper
文档字符串:包装函数的文档字符串
模块名:__main__
在函数调用之前
Hello, World!
在函数调用之后多个装饰器
一个函数可以应用多个装饰器,装饰器的应用顺序是从下到上(或从右到左)。
示例
python
# 多个装饰器
import functools
def decorator1(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("装饰器 1 开始")
result = func(*args, **kwargs)
print("装饰器 1 结束")
return result
return wrapper
def decorator2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("装饰器 2 开始")
result = func(*args, **kwargs)
print("装饰器 2 结束")
return result
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello, World!")
# 调用函数
say_hello()输出:
装饰器 1 开始
装饰器 2 开始
Hello, World!
装饰器 2 结束
装饰器 1 结束类装饰器
除了函数装饰器,Python 还支持类装饰器。类装饰器是一个类,它实现了 __call__ 方法,用于包装函数。
示例
python
# 类装饰器
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, World!")
# 调用函数
say_hello()输出:
在函数调用之前
Hello, World!
在函数调用之后带参数的类装饰器
python
# 带参数的类装饰器
class Repeat:
def __init__(self, n):
self.n = n
def __call__(self, func):
def wrapper(*args, **kwargs):
for i in range(self.n):
print(f"第 {i+1} 次调用")
result = func(*args, **kwargs)
return result
return wrapper
@Repeat(3)
def say_hello():
print("Hello, World!")
# 调用函数
say_hello()输出:
第 1 次调用
Hello, World!
第 2 次调用
Hello, World!
第 3 次调用
Hello, World!装饰器的应用场景
装饰器在以下场景中特别有用:
- 日志记录:记录函数的调用时间、参数和返回值。
- 性能分析:测量函数的执行时间。
- 权限验证:验证用户是否有权限执行函数。
- 缓存:缓存函数的执行结果,避免重复计算。
- 异常处理:捕获并处理函数执行过程中的异常。
- 事务管理:确保函数执行的原子性。
日志记录示例
python
# 日志记录装饰器
import functools
import datetime
def logger(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
timestamp = datetime.datetime.now().isoformat()
print(f"[{timestamp}] 调用函数 {func.__name__},参数:{args}, {kwargs}")
result = func(*args, **kwargs)
print(f"[{timestamp}] 函数 {func.__name__} 返回:{result}")
return result
return wrapper
@logger
def add(a, b):
return a + b
@logger
def say_hello(name):
return f"Hello, {name}!"
# 调用函数
add(3, 5)
say_hello("Alice")输出:
[2024-01-01T00:00:00.000000] 调用函数 add,参数:(3, 5), {}
[2024-01-01T00:00:00.000000] 函数 add 返回:8
[2024-01-01T00:00:00.000000] 调用函数 say_hello,参数:('Alice',), {}
[2024-01-01T00:00:00.000000] 函数 say_hello 返回:Hello, Alice!性能分析示例
python
# 性能分析装饰器
import functools
import time
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
duration = end_time - start_time
print(f"函数 {func.__name__} 执行时间:{duration:.4f} 秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "Done"
@timer
def fast_function():
return "Done"
# 调用函数
slow_function()
fast_function()输出:
函数 slow_function 执行时间:1.0001 秒
函数 fast_function 执行时间:0.0000 秒权限验证示例
python
# 权限验证装饰器
import functools
def requires_permission(permission):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 模拟用户权限
user_permissions = ["read", "write"]
if permission in user_permissions:
print(f"权限验证通过,执行函数 {func.__name__}")
return func(*args, **kwargs)
else:
print(f"权限验证失败,缺少 {permission} 权限")
return None
return wrapper
return decorator
@requires_permission("read")
def read_data():
return "读取数据"
@requires_permission("write")
def write_data():
return "写入数据"
@requires_permission("delete")
def delete_data():
return "删除数据"
# 调用函数
print(read_data())
print(write_data())
print(delete_data())输出:
权限验证通过,执行函数 read_data
读取数据
权限验证通过,执行函数 write_data
写入数据
权限验证失败,缺少 delete 权限
None缓存示例
python
# 缓存装饰器
import functools
def cache(func):