但是 Flask 的两种 Context 分离更大的意义是为了非 web 应用的场合。Flask 官方文档中有这样一段话
The main reason for the application’s context existence is that in the past a bunch of functionality was attached to the request context for lack of a better solution. Since one of the pillars of Flask’s design is that you can have more than one application in the same Python process.
defapp_context(self):"""Binds the application only. For as long as the application is bound
to the current context the :data:`flask.current_app` points to that
application. An application context is automatically created when a
request context is pushed if necessary.
Example usage::
with app.app_context():
...
.. versionadded:: 0.9
"""return AppContext(self)
嗯,很简单,只是构建一个 AppContext 对象返回,然后我们看看相关的代码
classAppContext(object):"""The application context binds an application object implicitly
to the current thread or greenlet, similar to how the
:class:`RequestContext` binds request information. The application
context is also implicitly created if a request context is created
but the application is not on top of the individual application
context.
"""def__init__(self, app):
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 = 0defpush(self):"""Binds the app context to the current context."""
self._refcnt += 1if hasattr(sys, 'exc_clear'):
sys.exc_clear()
_app_ctx_stack.push(self)
appcontext_pushed.send(self.app)
defpop(self, exc=_sentinel):"""Pops the app context."""try:
self._refcnt -= 1if self._refcnt <= 0:
if exc is _sentinel:
exc = sys.exc_info()[1]
self.app.do_teardown_appcontext(exc)
finally:
rv = _app_ctx_stack.pop()
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
% (rv, self)
appcontext_popped.send(self.app)
def__enter__(self):
self.push()
return self
def__exit__(self, exc_type, exc_value, tb):
self.pop(exc_value)
if BROKEN_PYPY_CTXMGR_EXIT and exc_type isnotNone:
reraise(exc_type, exc_value, tb)
emmmm,首先 push 方法就是将自己推入 _app_ctx_stack ,而 pop 方法则是将自己从栈顶推出。然后我们看到两个方法含义就很明确了,在进入上下文管理器的时候,将自己推入栈,然后退出上下文管理器的时候,将自己推出。
The application context is created and destroyed as necessary. It never moves between threads and it will not be shared between requests. As such it is the perfect place to store database connection information and other things. The internal stack object is called flask._app_ctx_stack. Extensions are free to store additional information on the topmost level, assuming they pick a sufficiently unique name and should put their information there, instead of on the flask.g object which is reserved for user code.
大意就是说,数据库配置和其余的重要配置信息,就挂载 App 对象上。但是如果是一些用户代码,比如你不想一层层函数传数据的话,然后有一些变量需要传递,那么可以挂在 g 上。
同时前面说了,Flask 并不仅仅可以当做一个 Web Framework 使用,同时也可以用于一些非 web 的场合下。在这种情况下,如果 g 是属于 Request Context 的话,那么我们要使用 g 的话,那么就需要手动构建一个请求,这无疑是不合理的。