前言
之前在flask入门系列中大概写了flask的应用上下文和请求上下文,比较浅显,但我们后面要了解flask的运行机制,就必须先深入了解一下flask中的应用上下文和请求上下文,这节阿牛将继续带你从源码来剖解他的奥秘!
上下文源码分析
在site-packages中找到flask文件夹,在里面找到ctx.py文件,这里面放的就是上下文相关的一些内容!
如上图,点击左侧的结构后,很容易就能找到我们的应用上下文AppContext和RequestContext。
而AppContext是对我们flask核心对象的一个封装,我们可以看一下AppContext这个类的构造函数:
def __init__(self, app: "Flask") -> None:
self.app = app
self.url_adapter = app.create_url_adapter(None)
self.g = app.app_ctx_globals_class()
# Like request context, app contexts can be pushed multiple times
# but there a basic "refcount" is enough to track them.
self._refcnt = 0
可以看到这样一行代码: self.app = app,这里的app就是我们通过app = Flask(__name__)实例化的flask核心对象,flask将这个核心对象封装到了AppContext。
如上图,AppContext下面定义了四个方法,这四个方法其实是操作AppContext出栈入栈的,这里不细说,后面写flask的运行机制时我们还会提到。
接下来我们看看请求上下文RequestContext
可以看到RequestContext的构造函数也对我们的flask核心对象进行了的封装,并且还封装了request请求对象!
我们继续往下滑,如下图:
我们在RequestContext中也看到了四个和AppContext中一样的方法!也是栈结构
由此总结:Flask核心对象存储在AppContext中,Request请求对象在RequestContext中!
到这里可能有些人就有些疑惑了,我们直接操作这个Flask核心对象不好吗,为什么还要进行封装,这其实就涉及到了我们的设计模式,有时候我们设计了一个对象,但是我们发现有些参数是这个对象外部的,这时候我们就需要将这些参数和这个对象进行封装成一个新的对象,flask正好做了这么一件事,将Flask核心对象和一些外部参数进行封装成了AppContext,即上下文对象,RequestContext也是如此!
总结
看了源码,我们现在要搞清Flask, AppContext, Request, RequestContext的关系。
- Flask是我们的核心对象,核心对象里面承载了各种各样的功能,比如它保存了我们配置文件的信息,提供了注册路由、视图函数等一系列的功能。
- AppContext将Flask核心对象进行了封装,并且附加了额外的参数。
- Request对象保存了我们的请求信息,比如相关url的参数等。
- RequestContext将Request对象进行了封装,并且附加了额外的参数。
我们编码中往往使用的是Flask核心对象和Request对象,通过对源码的理解,我们现在可以想,我们不仅可以通过from ... import 导入的方式使用Flask核心对象和Request对象,而且还可以通过AppContext,RequestContext来间接获取,这就要提到flask运行机制的核心,就是LocalProxy(代理),好了,这里浅浅的提一下,我们下节再接着说哦!