flask源码剖析之上下文全局变量

flask源码剖析之上下文全局变量_第1张图片


flask源码剖析之上下文全局变量_第2张图片

flask有四个线程级的全局变量,两个是程序上下文变量:current_app和g,另外两个是请求上下文变量:request和session.

flask源码剖析之上下文全局变量_第3张图片


这四个变量只有从flask.globals中导入才可以使用,即

from flask import current_app

from flask import g

from flask import request

from flask import session


但是使用不意味着有效,要想有效,导入后还要再push程序上下文变量和请求上下文变量:

1)利用flask.app中的app.app_context()或app.request_context()方法建立AppContext(app)实例或RequestContext(...)实例;

      app_ctx       = app.app_context()

      request_ctx = app.request_context(...)

    def app_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)

    def request_context(self, environ):
        """Creates a :class:`~flask.ctx.RequestContext` from the given
        environment and binds it to the current context.  This must be used in
        combination with the `with` statement because the request is only bound
        to the current context for the duration of the `with` block.

        Example usage::

            with app.request_context(environ):
                do_something_with(request)

        The object returned can also be used without the `with` statement
        which is useful for working in the shell.  The example above is
        doing exactly the same as this code::

            ctx = app.request_context(environ)
            ctx.push()
            try:
                do_something_with(request)
            finally:
                ctx.pop()

        .. versionchanged:: 0.3
           Added support for non-with statement usage and `with` statement
           is now passed the ctx object.

        :param environ: a WSGI environment
        """
        return RequestContext(self, environ)

2)调用1)中建立的实例相应的push()方法——flask.ctx中;

      app_ctx.push( )

or   request_ctx.push( )    ???这个好像不需要???P12   

确实不需要,因为这是系统自动帮我们完成的!!!!具体参见文章Flask request,g,session的实现原理

class AppContext(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 = 0

    def push(self):
        """Binds the app context to the current context."""
        self._refcnt += 1
        _app_ctx_stack.push(self)
        appcontext_pushed.send(self.app)

    ......


3)2)中的push()方法实际上就是利用LocalStack()的实例_app_ctx_stack或_request_ctx_stack的push()方法——入栈。因此我们可以使用flask创建n个web app,而不会错乱。

一个web app有很多个request和session信息,使用_request_ctx_stack保存。

# -*- coding: utf-8 -*-
"""
    flask.globals
    ~~~~~~~~~~~~~

    Defines all the global objects that are proxies to the current
    active context.

    :copyright: (c) 2011 by Armin Ronacher.
    :license: BSD, see LICENSE for more details.
"""

from functools import partial
from werkzeug.local import LocalStack, LocalProxy


def _lookup_req_object(name):
    top = _request_ctx_stack.top
    if top is None:
        raise RuntimeError('working outside of request context')
    return getattr(top, name)


def _lookup_app_object(name):
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError('working outside of application context')
    return getattr(top, name)


def _find_app():
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError('working outside of application context')
    return top.app


# context locals

_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()

current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

4)因此,所谓的app_ctx.push()实质上是落实在LocalStack().push()即 _app_ctx_stack.push()之上的!


可参考文章Flask request,g,session的实现原理

你可能感兴趣的:(Web,flask,python)