• 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
  • 相关阅读:
    洛谷 P1706 全排列
    n皇后问题
    跳马
    [HDOJ4612]Warm up(双连通分量,缩点,树直径)
    [POJ3177]Redundant Paths(双连通图,割边,桥,重边)
    [POJ3352]Road Construction(缩点,割边,桥,环)
    [POJ3694]Network(LCA, 割边, 桥)
    [UVA796]Critical Links(割边, 桥)
    [UVA315]Network(tarjan, 求割点)
    [HDOJ2586]How far away?(最近公共祖先, 离线tarjan, 并查集)
  • 原文地址:https://www.cnblogs.com/yinwenjie/p/10905686.html
Copyright © 2020-2023  润新知