Python 装饰器的用法
1. 什么是装饰器?
装饰器(Decorator)是 Python 中的一个设计模式,它允许在不修改函数定义的情况下,向函数添加额外的功能。装饰器本质上是一个高阶函数,即接受函数作为参数并返回一个新函数。装饰器通常用于日志记录、性能测试、权限验证等场景。
装饰器的基本语法是通过在函数定义前加上 @decorator_name
来实现的。
2. 装饰器的定义与基本使用
示例1:最简单的装饰器
以下是一个最简单的装饰器示例,它在原函数调用前后打印日志信息。
def my_decorator(func):
def wrapper():
print("执行函数前的操作")
func()
print("执行函数后的操作")
return wrapper
# 使用装饰器
@my_decorator
def say_hello():
print("Hello, World!")
say_hello()
代码说明
my_decorator(func)
:这是装饰器函数,它接收另一个函数func
作为参数,并返回一个新的函数wrapper
。wrapper()
:在wrapper
函数中,我们在原函数调用前后添加了自定义操作。@my_decorator
:这一行代码相当于say_hello = my_decorator(say_hello)
。每当调用say_hello()
时,实际上执行的是wrapper()
函数。
输出
执行函数前的操作
Hello, World!
执行函数后的操作
3. 带参数的装饰器
装饰器不仅可以作用于无参函数,还可以处理带参数的函数。
示例2:处理带参数的函数
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")
代码说明
*args, **kwargs
:这是 Python 中用于接收任意数量的位置参数和关键字参数的语法。通过它,装饰器可以处理各种参数组合的函数。func(*args, **kwargs)
:将原函数的参数传递给它。
输出
执行函数前的操作
Hello, Alice!
执行函数后的操作
4. 多个装饰器的使用
在 Python 中,你可以对同一个函数应用多个装饰器。装饰器的执行顺序是从内向外,即最靠近函数的装饰器最先执行。
示例3:多个装饰器的应用
def decorator_1(func):
def wrapper():
print("装饰器1 - 前")
func()
print("装饰器1 - 后")
return wrapper
def decorator_2(func):
def wrapper():
print("装饰器2 - 前")
func()
print("装饰器2 - 后")
return wrapper
@decorator_1
@decorator_2
def say_hello():
print("Hello!")
say_hello()
代码说明
- 装饰器应用顺序:
@decorator_2
最先应用,所以decorator_2
包裹了原函数say_hello
。然后decorator_1
包裹了decorator_2
的返回结果。
输出
装饰器1 - 前
装饰器2 - 前
Hello!
装饰器2 - 后
装饰器1 - 后
5. 装饰器的实际应用
5.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 example_function():
time.sleep(2)
example_function()
代码说明
time.time()
:记录当前时间,函数执行前后都调用该函数,计算两者差值即为执行时间。
输出
函数 example_function 执行时间: 2.0001 秒
5.2 权限验证
装饰器在 Web 开发中常用于权限验证。假设我们需要验证某个用户是否具有执行某项操作的权限,可以使用装饰器实现。
def check_permission(user_role):
def decorator(func):
def wrapper(*args, **kwargs):
if user_role != 'admin':
print("权限不足,无法执行此操作")
return
return func(*args, **kwargs)
return wrapper
return decorator
@check_permission(user_role='admin')
def delete_user():
print("用户已删除")
@check_permission(user_role='guest')
def add_user():
print("用户已添加")
delete_user() # admin 执行操作
add_user() # guest 尝试执行操作
代码说明
check_permission(user_role)
:这是一个带参数的装饰器,用来检查用户的角色是否为 ‘admin’,如果权限不足则阻止函数执行。
输出
用户已删除
权限不足,无法执行此操作
6. 装饰器实现的缓存机制
通过装饰器实现缓存(memoization)可以提高函数的效率,尤其是在处理耗时计算时。
def memoize(func):
cache = {
}
def wrapper(n):
if n not in cache:
cache[n] = func(n)
return cache[n]
return wrapper
@memoize
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 输出55
代码说明
cache
:使用字典缓存已计算的 Fibonacci 结果,避免重复计算,提高效率。
7. 带参数的装饰器
装饰器本身可以接受参数。通过这一功能,我们可以创建更加灵活的装饰器。
示例:带参数的装饰器
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()
代码说明
repeat(times)
:这是一个装饰器工厂,接收参数times
,并生成真正的装饰器decorator
。for _ in range(times)
:函数被调用多次,次数由装饰器的参数决定。
输出
Hello!
Hello!
Hello!
8. 结论
Python 装饰器是一个功能强大且灵活的工具,能够为函数添加额外功能,而无需修改函数本身。它通过封装逻辑,使代码更加简洁和可维护。装饰器特别适合用于日志记录、权限验证、性能分析等应用场景。尽管装饰器的使用非常灵活,但在代码过度复杂的情况下,应避免滥用装饰器,以保持代码的可读性。