Python装饰器是一种强大的工具,用于在不修改原有函数代码的基础上为其添加额外的功能。以下是一些具体使用装饰器的示例:
示例1:日志记录
装饰器可以用来为函数添加日志记录功能,以便追踪函数的调用情况。
import logging
def log_decorator(func):
def wrapper(*args, **kwargs):
logging.info(f"Calling function {func.__name__} with args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
logging.info(f"Function {func.__name__} returned: {result}")
return result
return wrapper
@log_decorator
def calculate_sum(a, b):
return a + b
calculate_sum(3, 5) # 输出类似:Calling function calculate_sum with args=(3, 5), kwargs={}
# Function calculate_sum returned: 8
在这个例子中,log_decorator 装饰器会在调用 calculate_sum 函数前后分别记录一条日志,显示函数名、传入的参数和返回的结果。
示例2:性能计时
装饰器可以用来测量函数的执行时间,有助于性能分析和优化。
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
execution_time = end_time - start_time
print(f"Function {func.__name__} executed in {execution_time:.6f} seconds")
return result
return wrapper
@timer_decorator
def process_data(data):
# 复杂的数据处理逻辑
pass
process_data(some_large_dataset) # 输出类似:Function process_data executed in 1.234567 seconds
timer_decorator 装饰器在调用 process_data 函数前后记录开始和结束时间,计算并打印出函数的执行时间。
示例3:权限检查
装饰器可以用于实现函数级别的权限检查,确保只有授权用户才能执行某些操作。
def login_required(func):
def wrapper(user, *args, **kwargs):
if not user.is_authenticated:
raise AuthenticationError("User must be logged in to perform this action.")
return func(user, *args, **kwargs)
return wrapper
class User:
def __init__(self, is_authenticated=False):
self.is_authenticated = is_authenticated
@login_required
def edit_profile(user):
# 编辑用户个人资料的逻辑
pass
user = User(is_authenticated=True)
edit_profile(user) # 正常执行
user = User(is_authenticated=False)
edit_profile(user) # 抛出 AuthenticationError
login_required 装饰器检查传入的 user 是否已登录,若未登录则抛出异常。这样,只需在需要权限控制的函数上使用该装饰器,即可实现一致的权限检查逻辑。
示例4:缓存结果
装饰器可以用于缓存函数的返回结果,避免重复计算,提高性能。
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(30)) # 第一次调用会计算结果,后续调用相同参数时直接返回缓存结果
在这个例子中,使用了Python标准库中的 functools.lru_cache 装饰器,它会缓存最近计算过的 fibonacci 函数的结果,当再次以相同参数调用时,直接返回缓存的值,而不是重新计算。
以上四个示例演示了Python装饰器在日志记录、性能计时、权限检查和结果缓存等场景中的应用,体现了装饰器在简化代码、增强功能和提高性能方面的价值。
下面介绍一下Python装饰器常用的使用技巧:
1. 带有参数的装饰器
装饰器通常不直接接收参数,但如果需要为装饰器提供额外配置,可以创建一个返回装饰器的工厂函数:
from functools import wraps
def cache(ttl=60):
"""带有缓存过期时间参数的装饰器"""
def decorator(func):
@wraps(func) # 保持被装饰函数的元信息
def wrapper(*args, **kwargs):
# 这里省略具体的缓存逻辑,如使用键值对存储结果
result = get_from_cache(args, kwargs) or calculate_result(func, *args, **kwargs)
set_to_cache(args, kwargs, result, ttl=ttl)
return result
return wrapper
return decorator
@cache(ttl=30)
def expensive_computation(a, b):
"""耗时的计算函数"""
# 实现复杂的计算逻辑
pass
在这个例子中,cache 函数接收一个 ttl 参数(缓存过期时间),返回一个真正的装饰器 decorator。这样,我们就可以根据需要为不同的函数指定不同的缓存过期时间。
2. 多个装饰器的组合(复合装饰器)
一个函数可以被多个装饰器依次包装,形成装饰器链。这种组合方式使得不同功能的装饰器可以叠加应用于同一个函数:
def log_call(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned: {result}")
return result
return wrapper
def authenticate(user_level='basic'):
def decorator(func):
def wrapper(*args, **kwargs):
check_user_auth(user_level)
return func(*args, **kwargs)
return wrapper
return decorator
@authenticate(user_level='admin')
@log_call
def update_database(data):
"""更新数据库操作"""
# 实现数据库更新逻辑
pass
此处,update_database 函数先经过 authenticate 装饰器进行用户身份验证,然后再由 log_call 装饰器记录函数调用情况。装饰器的执行顺序遵循从上到下的应用顺序。
3. 类装饰器
类也可以作为装饰器使用,尤其适用于需要保存状态或执行更复杂逻辑的情况:
class RateLimiter:
def __init__(self, max_calls_per_minute=60):
self.calls_made = 0
self.max_calls_per_minute = max_calls_per_minute
self.reset_time = time.time() + 60
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
if self.calls_made < self.max_calls_per_minute:
self.calls_made += 1
return func(*args, **kwargs)
elif time.time() >= self.reset_time:
self.calls_made = 1
self.reset_time = time.time() + 60
return func(*args, **kwargs)
else:
raise RateLimitExceeded("Rate limit exceeded.")
return wrapper
@RateLimiter(max_calls_per_minute=30)
def send_email(to, subject, body):
"""发送电子邮件函数"""
# 实现邮件发送逻辑
pass
RateLimiter 类作为一个装饰器,限制了 send_email 函数每分钟的最大调用次数。类装饰器的优势在于可以利用类的特性(如类变量和方法)来保存和管理状态。
4. 使用第三方库提供的装饰器
许多Python库(如Flask、Django、pytest等)提供了现成的装饰器,简化常见任务的实现。例如,Flask中的路由装饰器:
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/api/users', methods=['GET'])
def list_users():
"""定义一个处理GET请求的路由"""
users = fetch_users_from_database()
return jsonify(users)
这里,@app.route 是Flask提供的装饰器,它将 list_users 函数与指定的URL路径和HTTP方法关联起来,无需手动处理HTTP请求和响应。
以上就是Python装饰器的一些使用技巧示例,包括带有参数的装饰器、复合装饰器、类装饰器以及使用第三方库提供的装饰器,它们展示了装饰器在实际编程中如何帮助我们简洁、高效地实现多种功能。