前言
在 Python 中,编写有参数的装饰器是一种更高级的技术,它允许我们在装饰器中传递额外的参数,从而实现更灵活的功能。有参数的装饰器可以用于配置装饰器的行为,例如设置日志级别、指定缓存策略等。
1. 带参数的日志记录装饰器
假设我们需要编写一个带参数的日志记录装饰器,用于记录函数的调用和返回值,并指定日志级别。
1.1 示例代码
import logging
def log(level):
def decorator(func):
def wrapper(*args, **kwargs):
logging.log(level, f"Calling function '{func.__name__}'")
result = func(*args, **kwargs)
logging.log(level, f"Function '{func.__name__}' returned {result}")
return result
return wrapper
return decorator
@log(logging.DEBUG)
def debug_function():
return "Debug message"
@log(logging.INFO)
def info_function():
return "Info message"
logging.basicConfig(level=logging.DEBUG)
debug_result = debug_function()
info_result = info_function()
print(debug_result) # 输出:Debug message
print(info_result) # 输出:Info message
在这个例子中,log 装饰器接受一个日志级别作为参数,并返回一个真正的装饰器函数。
2. 带参数的性能统计装饰器
假设我们需要编写一个带参数的性能统计装饰器,用于记录函数的执行时间和次数,并指定统计的精度。
2.1 示例代码
import time
def performance_stats(precisinotallow=4):
def decorator(func):
call_count = 0
total_time = 0.0
def wrapper(*args, **kwargs):
nonlocal call_count, total_time
start_time = time.time()
print(f"Calling function '{func.__name__}'")
result = func(*args, **kwargs)
end_time = time.time()
elapsed_time = round(end_time - start_time, precision)
total_time += elapsed_time
call_count += 1
print(f"Function '{func.__name__}' returned {result} in {elapsed_time:.{precision}f} seconds")
print(f"Total calls: {call_count}, Total time: {total_time:.{precision}f} seconds")
return result
return wrapper
return decorator
@performance_stats(precisinotallow=2)
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
result = factorial(5)
print(result) # 输出:120
在这个例子中,performance_stats 装饰器接受一个精度参数,并返回一个真正的装饰器函数。
3. 带参数的身份验证装饰器
假设我们需要编写一个带参数的身份验证装饰器,用于检查用户是否已登录,并指定允许的用户名。
3.1 示例代码
users = {
"alice": "password123",
"bob": "secret456"
}
def login_required(allowed_users):
def decorator(func):
def wrapper(username, password, *args, **kwargs):
if username in allowed_users and allowed_users[username] == password:
print(f"User '{username}' authenticated")
return func(username, *args, **kwargs)
else:
print("Authentication failed")
return None
return wrapper
return decorator
@login_required(users)
def view_profile(username):
return f"Profile of user '{username}'"
result = view_profile("alice", "password123")
print(result) # 输出:Profile of user 'alice'
result = view_profile("bob", "wrongpass")
print(result) # 输出:None
在这个例子中,login_required 装饰器接受一个允许的用户名字典,并返回一个真正的装饰器函数。
4. 带参数的缓存装饰器
假设我们需要编写一个带参数的缓存装饰器,用于缓存函数的结果,并指定缓存的大小。
4.1 示例代码
from collections import OrderedDict
def memoize(cache_size=100):
cache = OrderedDict()
def decorator(func):
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
if key not in cache:
print(f"Computing {func.__name__}({args}, {kwargs})")
result = func(*args, **kwargs)
cache[key] = result
if len(cache) > cache_size:
cache.popitem(last=False)
else:
print(f"Retrieving {func.__name__}({args}, {kwargs}) from cache")
return cache[key]
return wrapper
return decorator
@memoize(cache_size=10)
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n - 1) + fibonacci(n - 2)
result = fibonacci(10)
print(result) # 输出:55
在这个例子中,memoize 装饰器接受一个缓存大小参数,并返回一个真正的装饰器函数。
5. 带参数的日志记录装饰器
假设我们需要编写一个带参数的日志记录装饰器,用于记录函数的调用和返回值,并指定日志文件。
5.1 示例代码
import logging
def log_to_file(log_file):
logging.basicConfig(filename=log_file, level=logging.DEBUG, format='%(asctime)s %(message)s')
def decorator(func):
def wrapper(*args, **kwargs):
logging.info(f"Calling function '{func.__name__}'")
result = func(*args, **kwargs)
logging.info(f"Function '{func.__name__}' returned {result}")
return result
return wrapper
return decorator
@log_to_file("example.log")
def debug_function():
return "Debug message"
debug_result = debug_function()
with open("example.log", "r") as file:
log_content = file.read()
print(log_content)
在这个例子中,log_to_file 装饰器接受一个日志文件名参数,并返回一个真正的装饰器函数。
6. 总结
通过以上示例,我们详细介绍了如何编写有参数的装饰器,并给出了具体的示例代码:
- 带参数的日志记录装饰器:记录函数的调用和返回值,并指定日志级别。
- 带参数的性能统计装饰器:记录函数的执行时间和次数,并指定统计的精度。
- 带参数的身份验证装饰器:检查用户是否已登录,并指定允许的用户名。
- 带参数的缓存装饰器:缓存函数的结果,并指定缓存的大小。
- 带参数的日志记录装饰器:记录函数的调用和返回值,并指定日志文件。