Python編寫有參數(shù)的decorator
前言
在 Python 中,編寫有參數(shù)的裝飾器是一種更高級的技術(shù),它允許我們在裝飾器中傳遞額外的參數(shù),從而實現(xiàn)更靈活的功能。有參數(shù)的裝飾器可以用于配置裝飾器的行為,例如設(shè)置日志級別、指定緩存策略等。
1. 帶參數(shù)的日志記錄裝飾器
假設(shè)我們需要編寫一個帶參數(shù)的日志記錄裝飾器,用于記錄函數(shù)的調(diào)用和返回值,并指定日志級別。
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 裝飾器接受一個日志級別作為參數(shù),并返回一個真正的裝飾器函數(shù)。
2. 帶參數(shù)的性能統(tǒng)計裝飾器
假設(shè)我們需要編寫一個帶參數(shù)的性能統(tǒng)計裝飾器,用于記錄函數(shù)的執(zhí)行時間和次數(shù),并指定統(tǒng)計的精度。
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 裝飾器接受一個精度參數(shù),并返回一個真正的裝飾器函數(shù)。
3. 帶參數(shù)的身份驗證裝飾器
假設(shè)我們需要編寫一個帶參數(shù)的身份驗證裝飾器,用于檢查用戶是否已登錄,并指定允許的用戶名。
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 裝飾器接受一個允許的用戶名字典,并返回一個真正的裝飾器函數(shù)。
4. 帶參數(shù)的緩存裝飾器
假設(shè)我們需要編寫一個帶參數(shù)的緩存裝飾器,用于緩存函數(shù)的結(jié)果,并指定緩存的大小。
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 裝飾器接受一個緩存大小參數(shù),并返回一個真正的裝飾器函數(shù)。
5. 帶參數(shù)的日志記錄裝飾器
假設(shè)我們需要編寫一個帶參數(shù)的日志記錄裝飾器,用于記錄函數(shù)的調(diào)用和返回值,并指定日志文件。
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 裝飾器接受一個日志文件名參數(shù),并返回一個真正的裝飾器函數(shù)。
6. 總結(jié)
通過以上示例,我們詳細介紹了如何編寫有參數(shù)的裝飾器,并給出了具體的示例代碼:
- 帶參數(shù)的日志記錄裝飾器:記錄函數(shù)的調(diào)用和返回值,并指定日志級別。
- 帶參數(shù)的性能統(tǒng)計裝飾器:記錄函數(shù)的執(zhí)行時間和次數(shù),并指定統(tǒng)計的精度。
- 帶參數(shù)的身份驗證裝飾器:檢查用戶是否已登錄,并指定允許的用戶名。
- 帶參數(shù)的緩存裝飾器:緩存函數(shù)的結(jié)果,并指定緩存的大小。
- 帶參數(shù)的日志記錄裝飾器:記錄函數(shù)的調(diào)用和返回值,并指定日志文件。