Context(上下文)
上下文的中文解释:即语境、语意,是语言学科(语言学、社会语言学、篇章分析、语用学、符号学等)的概念。
比如,把一整段文字中某一句话单独来看,可能会让人丈二和尚摸不着头脑,产生不同的理解,但是放在整段文字当中时,你就很容易理解是什么意思,不会产生歧义。反过来,同样的一句话放在不同段落里边,产生的意思也会不一样,而这个段落就可以理解为上下文,也就是上文解释中的语境。
在计算机程序里边,上下文可以理解为程序所运行时的环境,这个环境具体来说可以说是变量和传进来的参数。一般来讲,我们所设计的函数都不是单独的,都会有很多的外部变量,缺乏这些变量,函数就没法运行,只有把这些变量赋值传到函数中,才能正确执行函数,而这些赋值的集合就叫做上下文。
Flask 中的Application Context(程序上下文)和Request Context(请求上下文)
1、Application 就是调用 app = Flask(__name__) 时创建的app对象。
2、Request 指每次http请求发生时,WSGI server 调用Flask.call()之后,在Flask对象内部创建的Request对象
3、application 的生命周期大于request,一个application存活期间,可能发生多次http 请求
from flask import request
@app.route('/')
def index():
user_agent = reqeust.headers.get('User-Agent')
return user_agent
理解请求钩子:
@before_first_request :注册一个函数,在处理第一个请求前运行
@before_request :注册一个函数,在每次请求前运行
@after_request :注册一个函数,如果没有未处理的异常抛出,在每次请求后运行
@teardown_request :注册一个函数,即使有未处理的异常抛出,也在每次请求后运行
在每个请求上下文的函数中,我们都可以访问request对象,然而request对象并不是全局变量,离开了请求的生命周期,上下文环境不在了,也就无法获取request对象了,而上面的四中hook函数,会挂载在生命周的不同阶段。
下面这段代码就会抛出RuntimeError:working outside of request context
def handle_request():
print request.url
handle_request()
可以使用Flask的内部方法request_context()来构建一个请求上下文
from werkzeug.text import EnvironBuilder
ctx = app.request_context(EnvironBuilder('/','http://localhost/').get_environ())
ctx.push()
try:
print request.url
finally:
ctx.pop()
Thread Local
对象是保存状态的地方,在Python中,一个对象的状态都被保存在对象携带的一个字典中,**Thread Local **则是一种特殊的对象,它的“状态”对线程隔离 —— 也就是说每个线程对一个 Thread Local 对象的修改都不会影响其他线程。这种对象的实现原理也非常简单,只要以线程的 ID 来保存多份状态字典即可,就像按照门牌号隔开的一格一格的信箱。
在Python中获取Thread Local最简单的方式是threading.local()
Flask是一个基于WerkZeug实现的框架,因此Flask的App Context和Request Context是基于WerkZeug的Local Stack的实现。这两种上下文对象类定义在flask.ctx中,ctx.push会将当前的上下文对象压栈压入flask._request_ctx_stack中,这个_request_ctx_stack同样也是个Thread Local对象,也就是在每个线程中都不一样,上下文压入栈后,再次请求的时候都是通过_request_ctx_stack.top在栈的顶端取,所取到的永远是属于自己线程的对象,这样不同线程之间的上下文就做到了隔离。请求结束后,线程退出,ThreadLocal本地变量也随即销毁,然后调用ctx.pop()弹出上下文对象并回收内存。