Python 21 Flask(二)上下文管理详解

上下文管理

对于上下文管理我没有找到明确的定义,但是经过源码流程的学习后,我觉得所谓的上下文管理应该就是Flask对请求和应用相关数据的一种处理方式,它不是像Django一样通过参数的传导,而是创建了全局变量直接引用,Flask为每个线程开辟一块独立的内存空间,将请求和应用相关的信息放到这个空间中,全局变量直接从这个空间中取出数据。

 

一、上下文管理流程梳理:

 

二、上下文管理图示:

 

三、源码分析

try:
    from greenlet import getcurrent as get_ident
except ImportError:
    try:
        from thread import get_ident
    except ImportError:
        from _thread import get_ident


class Local(object):
    __slots__ = ("__storage__", "__ident_func__")    #表示只能有这两个变量

    def __init__(self):
        object.__setattr__(self, "__storage__", {})
        object.__setattr__(self, "__ident_func__", get_ident)    #这里调用父类的方法

    def __iter__(self):
        return iter(self.__storage__.items())

    def __call__(self, proxy):
        """Create a proxy for a name."""
        return LocalProxy(self, proxy)

    def __release_local__(self):
        self.__storage__.pop(self.__ident_func__(), None)

    def __getattr__(self, name):
        try:
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value
        except KeyError:
            storage[ident] = {name: value}

    def __delattr__(self, name):
        try:
            del self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)
Local对象
class LocalStack(object):
    def __init__(self):
        self._local = Local()

    def push(self, obj):
        """Pushes a new item to the stack"""
        rv = getattr(self._local, "stack", None)
        if rv is None:
            self._local.stack = rv = []
        rv.append(obj)
        return rv

    def pop(self):
        """Removes the topmost item from the stack, will return the
        old value or `None` if the stack was already empty.
        """
        stack = getattr(self._local, "stack", None)
        if stack is None:
            return None
        elif len(stack) == 1:
            release_local(self._local)
            return stack[-1]
        else:
            return stack.pop()

    @property
    def top(self):
        """The topmost item on the stack.  If the stack is empty,
        `None` is returned.
        """
        try:
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None
LocalStack对象
这个对象是帮助我们去Local中取ctx或app_ctx对象的。
当我们调用request.method的时候,会调用LocalProxy对象的__getattr__方法,这个方法会用LocalStack取出ctx,然后用ctx.request.method取到数据返回。
其他的同理
LocalProxy对象

 

    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app` which can be
        wrapped to applying middleware."""
        return self.wsgi_app(environ, start_response)
1.请求进来执行__call__方法
    def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)
2.调用wsgi_app方法
ReuqestContext函数中封装了request数据和session
request通过传入environ原始数据实例化Request对象,处理这些原始数据,将处理好的数据返回给RequestContext的request
session一开始是空的,会去cookie中解密并反序列化
3.其中ctx就是实例化RequestContext对象
#实际上就是RequestContext(ctx).push()

#首先是实例化一个app_ctx对象,并将这个对象放入Local中
        if app_ctx is None or app_ctx.app != self.app:
            app_ctx = self.app.app_context()
            app_ctx.push()
            self._implicit_app_ctx_stack.append(app_ctx)
        else:
            self._implicit_app_ctx_stack.append(None)

#然后将ctx放入Local中
        _request_ctx_stack.push(self)
4.ctx.push

 

posted @ 2019-05-22 14:25  不可思议的猪  阅读(815)  评论(0编辑  收藏  举报