Sanic框架最佳实践:装饰器的高级应用
装饰器在Sanic中的重要性
在Python Web开发中,装饰器是一种强大的工具,它允许开发者在不修改原函数代码的情况下,为函数添加额外的功能。在Sanic这个异步Web框架中,装饰器尤为重要,它可以帮助我们构建更加清晰、可维护的API接口。
为什么使用装饰器
装饰器能够帮助我们实现DRY(Don't Repeat Yourself)原则,将通用功能从视图处理函数中抽离出来,例如:
- 权限验证
- 请求参数校验
- 用户信息注入
- 日志记录
- 性能监控
通过装饰器,我们可以将这些横切关注点与业务逻辑分离,使代码更加模块化。
基础装饰器示例
让我们从一个简单的授权验证装饰器开始:
from functools import wraps
from sanic.response import json
def authorized():
def decorator(f):
@wraps(f)
async def decorated_function(request, *args, **kwargs):
is_authorized = await check_request_for_authorization_status(request)
if is_authorized:
response = await f(request, *args, **kwargs)
return response
else:
return json({"status": "not_authorized"}, 403)
return decorated_function
return decorator
@app.route("/protected")
@authorized()
async def protected_handler(request):
return json({"status": "authorized"})
这个装饰器会检查请求的授权状态,如果未授权则返回403错误。
装饰器模板
为了帮助开发者快速实现各种装饰器,以下是三种常见模式的模板:
1. 带参数的装饰器
当装饰器需要配置参数时使用:
from inspect import isawaitable
from functools import wraps
def validate_params(arg1, arg2):
def decorator(f):
@wraps(f)
async def decorated_function(request, *args, **kwargs):
# 在这里使用arg1和arg2进行参数验证
response = f(request, *args, **kwargs)
if isawaitable(response):
response = await response
return response
return decorated_function
return decorator
@app.get("/data")
@validate_params(1, 2)
async def get_data(request):
return json({"data": "some data"})
2. 不带参数的装饰器
当装饰器不需要额外配置时使用:
def log_request(func):
def decorator(f):
@wraps(f)
async def decorated_function(request, *args, **kwargs):
print(f"Request received: {request.method} {request.path}")
response = f(request, *args, **kwargs)
if isawaitable(response):
response = await response
return response
return decorated_function
return decorator(func)
@app.get("/")
@log_request
async def home(request):
return text("Welcome")
3. 可选参数的装饰器
最灵活的方案,支持带参数或不带参数调用:
def cache_response(maybe_func=None, *, ttl=None):
def decorator(f):
@wraps(f)
async def decorated_function(request, *args, **kwargs):
# 使用ttl参数控制缓存时间
response = f(request, *args, **kwargs)
if isawaitable(response):
response = await response
return response
return decorated_function
return decorator(maybe_func) if maybe_func else decorator
# 带参数使用
@app.get("/news")
@cache_response(ttl=3600)
async def get_news(request):
return json({"news": "latest"})
# 不带参数使用
@app.get("/status")
@cache_response
async def get_status(request):
return json({"status": "ok"})
最佳实践建议
-
保持装饰器单一职责:每个装饰器应该只做一件事,这样更容易维护和组合使用。
-
使用functools.wraps:这可以保留原始函数的元数据,如函数名、文档字符串等。
-
考虑异步支持:Sanic是异步框架,确保装饰器能正确处理异步函数。
-
错误处理:在装饰器中添加适当的错误处理逻辑,避免影响主流程。
-
性能考量:装饰器会增加调用栈深度,对于性能敏感的场景要谨慎使用。
通过合理使用装饰器,可以大幅提升Sanic应用的可维护性和代码复用率。希望这些模板和最佳实践能帮助你在项目中更有效地使用装饰器。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考