zoukankan      html  css  js  c++  java
  • LocalStack和Local对象实现栈的管理

    flask里面有两个重要的类Local和LocalStack

    输入from flask import globals

    左键+ctrl点globals进入源码,进去后找57行

    flask只会实例化出这两个 LocalStack的类,_request_ctx_stack = LocalStack(),_app_ctx_stack = LocalStack(),这两个相同的类装不同的内容,完成不同的功能

     这两个类都找到了.在往上看,找关于get_ident的源码.

    在最上方找关于get_ident的源码:
    try:
            from greenlet import getcurrent as get_ident # getcurrent他可以为每一个协程标记一个ID
    except ImportError:
            try:
                    from thread import get_ident  #这里我们用的是线程的id
            except ImportError:
                    from _thread import get_ident 
    
    
    上面的源码可以理解为: from threading import get_ident 

    Loacl类

    再看一下Local类的源码:

    Local的源码:
    class Local(object):
            __slots__ = ("__storage__", "__ident_func__")                   #就是指明Local可以.这两种方法
    
            def __init__(self):
                    object.__setattr__(self, "__storage__", {})             #相当于 self.__storage__={}
                    object.__setattr__(self, "__ident_func__", get_ident)   #相当于 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__()                             #取到线程id1111
                    storage = self.__storage__
                    try:
                            storage[ident][name] = value                      #造出{111:{x1:123}},name=x1
                    except KeyError:
                            storage[ident] = {name: value}          #取走123,当LocalStack()实例化对象过来时setattr方法就维护了111:{'stack':[]} statck是固定值,LoaclStack传过来的
            
            def __delattr__(self, name):
                    try:
                            del self.__storage__[self.__ident_func__()][name]
                    except KeyError:
                            raise AttributeError(name)
    
    当local=Local()时看init
    local.x1=123执行__setattr__
    local.x1找getattr
    
    这个Local类会建立一个字典:
    """
    __storage__ = {
    1111:{"stack":['陈说','龙龙'] }
    }
    """

    LocalStack类:

    就在Local类下面,看下LocalStack源码:

    class LocalStack(object):
            def __init__(self):
                    self._local = Local()                      #实例化一个Local的对象
    
            def __release_local__(self):
                    self._local.__release_local__()
    
            def _get__ident_func__(self):
                    return self._local.__ident_func__
    
            def _set__ident_func__(self, value):
                    object.__setattr__(self._local, "__ident_func__", value)
    
            __ident_func__ = property(_get__ident_func__, _set__ident_func__)
            del _get__ident_func__, _set__ident_func__
    
            def __call__(self):
                    def _lookup():
                            rv = self.top
                            if rv is None:
                                    raise RuntimeError("object unbound")
                            return rv
    
                    return LocalProxy(_lookup)
    
            def push(self, obj):
                    rv = getattr(self._local, "stack", None) #self._local.stack 触发Local类的getattr方法,其中self._local是Local的对象,就找Local类中的getattr,Local的getattr返回None
                    # rv = None
                    if rv is None:
                           self._local.stack = rv = []       #这句话的意思是rv=[],self._local.stack=[],就是给[]赋两个值,rv和stack共用[],这里会找Local的setattr,name=stack,value=[]
                    rv.append(obj)                           #obj就是obj.push('成说')传过来的陈说,[]==>['陈说']
                    return rv
    
            def pop(self):
                    stack = getattr(self._local, "stack", None)  #取到列表['陈说','龙龙']
                    if stack is None:
                            return None
                    elif len(stack) == 1:   #简单来说就是当你列表中只有一个值时,你来pop,就销毁statck
    #如果del __storage__[1111]里面加上线程id就销毁了这个id包括所对应的值,只剩__storage__ = {},并且返回最后一个列表中的值,具体功能在release_local中实现的
                            release_local(self._local)                         return stack[-1]                 else:                         return stack.pop() #删除['陈说','龙龙']中的'龙龙',         @property         def top(self):                 try:                         return self._local.stack[-1] #找Local的getattr,拿到 {1111:{"stack":['陈说','龙龙'] }}列表中的-1位置的内容.-1位置就是栈顶(后进先出,弹夹)                 except (AttributeError, IndexError):                         return None obj=LocalStack()找init obj.push('陈说') 找push方法 obj.push('龙龙') 找push方法 print(obj.top)找LocalStack()的top obj.pop找LocalStack()的pop 再obj.pop,就再删除

    Local类和LocalStack类关系总结:

    总结(要记一记):
    ①在flask中有个local类,他和threading.local的功能一样,为每个线程开辟空间进行存取数据,内部实现机制:内部维护一个字典__storage__ = {},
    然后线程id(或协程id)为key(是为了数据隔离,进程(协程)id之间的数据是隔离开的)后面的value为一个字典(键和值就是看你传的内容),如:
    __storage__ = {1211:{'k1':123}}         obj = Local()         obj.k1 = 123 ②在flask中还有一个LocalStack的类,他内部会依赖local对象,local对象负责存储数据,localstack对象用于将local中的值维护成一个栈,
    然后进行数据交互.如果没有这个LocalStack类,Local类一样可以使用,但只能存一个字典key:value,而LocalStack类是帮我们把字典变成列表(这样就有了栈的功能)     
    __storage__ = {1211:{'stack':['k1','k2']}}     obj= LocalStack()         obj.push('k1') obj.push('k2')         obj.top         obj.pop()

     flask中实例化的两个LocalStack的对象

    这两个类_request_ctx_stack = LocalStack(),_app_ctx_stack = LocalStack()就是flask实例化的LocalStack的对象,下面我们看一下这俩类是干啥的.

    from flask import globals

    左键+ctrl点globals点进去,找57和58行,这两个类出现了.

    请求上下文管理:
    _request_ctx_stack = LocalStack() #这个对象要放的内容:request和session封装到一个对象中去,并把对象装到列表中. __storage__ = {     1111:{'stack':[RequestContext(reqeust,session),]}, #将RequestContext(reqeust,session)对象封装俩值再放到列表中         1123:{'stack':[RequestContext(reqeust,session),]}, }
    应用上下文管理: _app_ctx_stack
    = LocalStack() #这个对象要放的内容:app和g封装到一个对象中去,并把对象放到列表中. __storage__ = {     1111:{'stack':[AppContenxt(app,g),]} #app就是Flask(__name__)实例化的对象         1123:{'stack':[AppContenxt(app,g),]}, #将AppContenxt(app,g)对象封装俩值再放到列表中 }

    图解flask整体概要:

    右边四块整体是LocalStack的两个实例化对象_request_ctx_stack和_app_ctx_stack,(还有关联的两个Local()类)

    在LocalStack()中有self._local=Local(),就关联到了Local类.请求进来先走push方法,

    再到__setattr__,往__storage__中的列表中添加ctx对象还有app_ctx对象(分别添加在两个__storage__中).

    request.args先找top再找__getattr__最后获取到__storage__的列表中的对象中封装的属性.

    最后请求走出来时走pop请求再销毁stack.

  • 相关阅读:
    Sql Server 收缩日志文件原理及always on 下的实践
    SQL Agent服务无法启动如何破
    Sql Server Always On 读写分离配置方法
    SQL SERVER 9003错误解决方法 只适用于SQL2000
    SQL Server 数据库分离与附加
    SQL SERVER 的模糊查询 LIKE
    sqlserver 时间格式函数详细
    浅谈SQL Server中的三种物理连接操作
    谈一谈SQL Server中的执行计划缓存(下)
    asp.net获取当前系统的时间
  • 原文地址:https://www.cnblogs.com/shengjunqiye/p/11924321.html
Copyright © 2011-2022 走看看