目录
1、信号的作用
- Flask 信号是一种事件(event)机制,它可以让应用程序在特定的事件发生时自动触发预定义的操作。信号可以被看作是一种通知机制,当某个特定事件发生时,应用程序就会发送一个通知给所有注册了该事件的处理函数。
- Flask 中有多个内置的信号,比如请求开始、请求结束、每次请求后等,开发者也可以定义自己的信号。开发者可以在应用程序中注册一个或多个处理函数,当信号被触发时,这些处理函数就会被自动调用。这些处理函数可以执行任何操作,比如记录日志、发送邮件、更新数据库等等。
- 使用 Flask 信号的主要优点是可以将应用程序的不同部分解耦,使其更加模块化和灵活。通过注册不同的信号处理函数,可以将应用程序的不同功能分离开来,方便维护和扩展。此外,信号还可以帮助开发者实现更高级的功能,比如异步任务管理、缓存更新等等。
注意事项:信号本身不会有返回值,因为它不会影响原有流程的执行。
2、flask信号使用
版本说明:
- flask: 1.1.4
- Python:3.9
- flask底层信号的使用依赖于blinker模块,所以需要先安装blinker模块:
pip install blinker
- 我们可以进入flask的signals.py模块,查看flask预留那些信号钩子,我们就可以根据这些信号扩展我们需要的操作,flask预留实现的信号如下:
_signals = Namespace()
# Core signals. For usage examples grep the source code or consult
# the API documentation in docs/api.rst as well as docs/signals.rst
template_rendered = _signals.signal("template-rendered")
before_render_template = _signals.signal("before-render-template")
request_started = _signals.signal("request-started")
request_finished = _signals.signal("request-finished")
request_tearing_down = _signals.signal("request-tearing-down")
got_request_exception = _signals.signal("got-request-exception")
appcontext_tearing_down = _signals.signal("appcontext-tearing-down")
appcontext_pushed = _signals.signal("appcontext-pushed")
appcontext_popped = _signals.signal("appcontext-popped")
message_flashed = _signals.signal("message-flashed")
- 根据信号的命名我们很容易知道这个信号的作用,现在我们以request_start(请求开始触发该信号)为示例讲讲,信号的具体使用:
- 直接从signals.py模块下的request_start跳转到request_start的使用处,即request_started.send()的代码处,源码如下:
def full_dispatch_request(self):
# 首次请求到来时触发,全部的请求只触发一次也就是首次请求来时触发那一次
# 使用before_first_request装饰的函数
self.try_trigger_before_first_request_functions()
try:
# 请求开始前发送信号
request_started.send(self)
# 请求处理前预处理
rv = self.preprocess_request()
if rv is None:
# 执行视图函数
rv = self.dispatch_request()
except Exception as e:
# 发生异常情况下执行
rv = self.handle_user_exception(e)
# 处理上面的执行结果并返回
return self.finalize_request(rv)
- 从上面源码可以看出在请求开始前(也就是执行视图函数之前,此时请求上下文和应用上下文已经创建好了)预留了一个信号发送钩子。我们可以通过这个钩子打印请求开始处理视图函数的日志到控制台告诉我们执行到哪儿了,平时可以使用其debug代码,示例如下:
from flask import Flask, signals
# 创建app对象
app = Flask(__name__)
# 注册信号
# @signals.request_started.connect
def request_start(arg):
print(f"这里请求已经开始进入处理视图函数了, arg: {arg}")
# 注册信号,也可以使用上面装饰器的方式@signals.request_started.connect
signals.request_started.connect(request_start)
# 特殊装饰器装饰的函数
@app.before_request
def before_index():
print("在index视图函数之前执行")
# 视图函数
@app.route("/index")
def index():
print("index")
return "index"
if __name__ == '__main__':
# flask项目启动入口
app.run(debug=True)
# 访问index视图执行控制台打印结果如下:
这里请求已经开始进入处理视图函数了, arg: <Flask 'app'>
在index视图函数之前执行
index
- 上面就是信号的简单使用,其他信号的使用方式也是一样的,这里有几点注意事项:
- 1、注册信号可以使用装饰器的方式,也可以使用函数注册的方式
- 2、注册函数的参数需要和预留的信号钩子保持一致
- 3、注册函数不需要返回值,因为没有什么用处
- 4、注册函数和预留信号的参数对应,可以在注册函数中根据获取的参数做一些自定义处理