详解Python的Flask框架中的signals信号机制


Posted in Python onJune 13, 2016

Flask 提供了信号(Signals)功能,是一种消息分发机制。类似于钩子(Hooks)。使用信号功能可以降低程序的耦合,分解复杂的业务模型。例如在更新了产品数据后,可以发送一个信号。当有需要对产品数据进行处理的功能时,就可以捕获信号进行处理。比如要建立产品缓存,或是更新搜索索引等。

定义信号

Flask 信号功能使用了 Blinker 模块,所以需要先安装 Blinker 模块

pip install blinker

定义一个信号:

from blinker import Namespace
product_saved = Namespace()

也可以使用 Flask 包装的 singles 对象:

from flask.singles import Namespace

发送信号

发送信号需要带上 app 实例方法,示例如下:

product_saved.send(app, product=product)

app 后面可以添加要传递的参数,但必须以 name=value 的格式,不支持使用单个变量名的方式。

收接信号

接收信号可以使用 connect_via 装饰器函数:

@product_saved.connect_via(app)
def updateCache(app, product):
  print(product)

Flask 中有以下核心信号:

1.flask.template_rendered

这个信号发送于一个模板被渲染成功后。信号传递的template是模板的实例,context是环境对象是一个字典。

订阅示例:

def log_template_renders(sender, template, context, **extra):
  sender.logger.debug('Rendering template "%s" with context %s',
            template.name or 'string template',
            context)
from flask import template_rendered
template_rendered.connect(log_template_renders, app)

2.flask.request_started

这个信号发送于请求开始之前,且请求环境设置完成之后。因为请求环境已经绑定, 所以订阅者可以用标准的全局代理,如 request 来操作请求。

订阅示例:

def log_request(sender, **extra):
  sender.logger.debug('Request context is set up')
from flask import request_started
request_started.connect(log_request, app)
flask.request_finished

这个信号发送于向客户端发送响应之前。信号传递的response为将要发送的响应。

订阅示例:

def log_response(sender, response, **extra):
  sender.logger.debug('Request context is about to close down. '
            'Response: %s', response)
from flask import request_finished
request_finished.connect(log_response, app)
flask.got_request_exception

这个信号发送于请求进行中发生异常的时候。它的发送 早于 标准异常处理介于。 在调试模式下,虽然没有异常处理,但发生异常时也发送这个信号。信号传递的exception是异常对象。

订阅示例:

def log_exception(sender, exception, **extra):
  sender.logger.debug('Got exception during processing: %s', exception)
from flask import got_request_exception
got_request_exception.connect(log_exception, app)
flask.request_tearing_down

这个信号发送于请求崩溃的时候,不管是否引发异常。目前,侦听此信号的函数在一般 崩溃处理器后调用,但是没有什么东西可用。

订阅示例:

def close_db_connection(sender, **extra):
  session.close()from flask import appcontext_tearing_down
request_tearing_down.connect(close_db_connection, app)

在 Flask 版本 0.9 中,这还会传递一个exc关键字参数,如果这个参数存在的话。 这个参数是引发崩溃的异常的引用。

3.flask.appcontext_tearing_down

当应用环境崩溃时发送这个信号。这个信号总是会发送,甚至是因为一个异常引发的 崩溃。侦听这个信号的函数会在常规崩溃处理器后被调用,但是你无法回馈这个信号。

订阅示例:

def close_db_connection(sender, **extra):
  session.close()from flask import request_tearing_down
appcontext_tearing_down.connect(close_db_connection, app)

这还会传递一个exc关键字参数,如果这个参数存在的话。这个参数是引发崩溃的 异常的引用。

4.flask.appcontext_pushed

当一个应用的环境被压入时,应用会发送这个信号。这个信号通常用于在单元测试中 临时钩接信息。例如可以用于改变g对象中现存的资源。

用法示例:

from contextlib import contextmanagerfrom
flask import appcontext_pushed
@contextmanagerdef user_set(app, user):
  def handler(sender, **kwargs):
    g.user = user
  with appcontext_pushed.connected_to(handler, app):
    yield

在测试代码中这样写:

def test_user_me(self):
  with user_set(app, 'john'):
    c = app.test_client()
    resp = c.get('/users/me')
    assert resp.data == 'username=john'
New in version 0.10.

5.appcontext_popped

当一个应用的环境被弹出时,应用会发送这个信号。这个信号通常写成appcontext_tearing_down 信号。

6.flask.message_flashed

当应用闪现一个消息时会发出这个信号。message`参数是消息内容, `category参数是消息类别。

订阅示例:

recorded = []def record(sender, message, category, **extra):
  recorded.append((message, category))
from flask import message_flashed
message_flashed.connect(record, app)

小结
信号可以让你在一瞬间安全地订阅它们。例如,这些临时的订阅对测试很有帮助。使用信号时,不要让信号订阅者(接收者)发生异常,因为异常会造成程序中断。

Python 相关文章推荐
Python中的__new__与__init__魔术方法理解笔记
Nov 08 Python
浅谈python中的面向对象和类的基本语法
Jun 13 Python
python dict.get()和dict['key']的区别详解
Jun 30 Python
Python原始字符串与Unicode字符串操作符用法实例分析
Jul 22 Python
python lambda表达式(匿名函数)写法解析
Sep 16 Python
浅析Python __name__ 是什么
Jul 07 Python
Python调用jar包方法实现过程解析
Aug 11 Python
在 Python 中使用 MQTT的方法
Aug 18 Python
Python实战之实现康威生命游戏
Apr 26 Python
能让Python提速超40倍的神器Cython详解
Jun 24 Python
分析Python list操作为什么会错误
Nov 17 Python
Python可视化神器pyecharts绘制地理图表
Jul 07 Python
Python的Flask站点中集成xhEditor文本编辑器的教程
Jun 13 #Python
Flask的图形化管理界面搭建框架Flask-Admin的使用教程
Jun 13 #Python
Python的Flask框架中集成CKeditor富文本编辑器的教程
Jun 13 #Python
Linux中安装Python的交互式解释器IPython的教程
Jun 13 #Python
浅谈python中的面向对象和类的基本语法
Jun 13 #Python
深入理解python多进程编程
Jun 12 #Python
python中根据字符串调用函数的实现方法
Jun 12 #Python
You might like
PHP安装攻略:常见问题解答(三)
2006/10/09 PHP
php字符串分割函数explode的实例代码
2013/02/07 PHP
基于empty函数的判断详解
2013/06/17 PHP
php简单读取.vcf格式文件的方法示例
2017/09/02 PHP
php读取本地json文件的实例
2018/03/07 PHP
jquery 实现的全选和反选
2009/04/15 Javascript
jquery ajax执行后台方法
2010/03/18 Javascript
asp.net网站开发中用jquery实现滚动浏览器滚动条加载数据(类似于腾讯微博)
2012/03/14 Javascript
Extjs4中tree的拖拽功能(可以两棵树之间拖拽) 简单实例
2013/12/08 Javascript
js修改原型的属性使用介绍
2014/01/26 Javascript
对JavaScript的全文搜索实现相关度评分的功能的方法
2015/06/24 Javascript
浅析AngularJs HTTP响应拦截器
2015/12/28 Javascript
利用vue写todolist单页应用
2016/12/15 Javascript
Bootstrap的Carousel配合dropload.js实现移动端滑动切换图片
2017/03/10 Javascript
vue构建单页面应用实战
2017/04/10 Javascript
详解angularJS动态生成的页面中ng-click无效解决办法
2017/06/19 Javascript
vue项目实战总结篇
2018/02/11 Javascript
浅谈vue同一页面中拥有两个表单时,的验证问题
2018/09/18 Javascript
vue实现新闻展示页的步骤详解
2019/04/11 Javascript
基于JavaScript判断两个对象内容是否相等
2020/01/10 Javascript
如何基于filter实现网站整体变灰功能
2020/04/17 Javascript
Vue实现点击导航栏当前标签后变色功能
2020/08/19 Javascript
python查找第k小元素代码分享
2013/12/18 Python
Python开发中爬虫使用代理proxy抓取网页的方法示例
2017/09/26 Python
Python+selenium实现自动循环扔QQ邮箱漂流瓶
2018/05/29 Python
python调用c++传递数组的实例
2019/02/13 Python
Python基于opencv实现的简单画板功能示例
2019/03/04 Python
使用Windows批处理和WMI设置Python的环境变量方法
2019/08/14 Python
tensorboard显示空白的解决
2020/02/15 Python
购买中国最好的电子产品:Geekbuying
2018/03/13 全球购物
西部世纪.net笔试题面试题
2014/04/03 面试题
测绘工程专业求职信
2014/07/15 职场文书
2014年社区工作总结
2014/11/18 职场文书
2016暑期社会实践新闻稿
2015/11/25 职场文书
三严三实·严以用权心得体会
2016/01/12 职场文书
Springboot/Springcloud项目集成redis进行存取的过程解析
2021/12/04 Redis