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.
LocalStack和Local对象实现栈的管理的更多相关文章
- flask 源码专题(十一):LocalStack和Local对象实现栈的管理
目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于localstack的实现 3. 总结 04 LocalS ...
- 04 flask源码剖析之LocalStack和Local对象实现栈的管理
04 LocalStack和Local对象实现栈的管理 目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于l ...
- flask上下文管理相关-LocalStack 对象维护栈
LocalStack 对象维护栈 模拟 import threading """ storage = { 1232: {stack:[123,456]} } " ...
- 堆,栈,内存管理, 拓展补充-Geekband
8, 堆,栈,内存管理 栈: local objects 在离开作用域之后就会被消除. 堆: new MyClass 一直会存在 静态对象: static local object 作用域在 ...
- ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理
在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行代码就展示了一个基本工作原理.然而,要将这样的解决方案运用到实际生产环境,还有很 ...
- flask之请求与响应、闪现(阅后即焚)、请求扩展(before,after)、中间件、LOCAL对象、偏函数、
目录 1.flask请求与响应 2.闪现 3.请求扩展 4.中间件 5.LOCAL对象 6.偏函数 templates 1.flask请求与响应 from flask import Flask,req ...
- Flask补充--threading.local对象
目录 Local 局部变量 全局变量 使用threading.local() 自定义threading.local 函数版 面向对象版 通过setattr和getattr实现 每个对象有自己的存储空间 ...
- local 对象补充
昨日回顾 1 @app.before_first_request,再项目启动后接收到的第一个请求,会执行before_first_request,他再@app.before_request之前执行.他 ...
- [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系
原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...
随机推荐
- 趋势投资tz-proj springcloud (vue redis)
https://github.com/deadzq/tz-test-1 https://github.com/deadzq/tz-test-api-1 https://github.com/deadz ...
- PHP引用(&)
引用是什么 在 PHP 中引用意味着用不同的名字访问同一个变量内容.这并不像 C 的指针:例如你不能对他们做指针运算,他们并不是实际的内存地址.替代的是,引用是符号表别名.注意在PHP 中,变量名和变 ...
- 垃圾邮件分类实战(SVM)
1. 数据集说明 trec06c是一个公开的垃圾邮件语料库,由国际文本检索会议提供,分为英文数据集(trec06p)和中文数据集(trec06c),其中所含的邮件均来源于真实邮件保留了邮件的原有格式和 ...
- ES6基础入门之let、const
作者 | Jeskson来源 | 达达前端小酒馆 01 首先呢?欢迎大家来学习ES6入门基础let,const的基础知识内容.初始ECMA Script6. ESMAScript与JavaScript ...
- 你真的懂git 吗
Git 存储目录结构介绍 首先我们先从 Git 存储目录说起,通过 git init 创建一个空的 Git 仓库,具体操作如下图: 创建完成后进入 .git 目录,如下图所示: hooks 该目录用于 ...
- BigDecimal代码示例
在平常开发中,如果涉及到计算,要求准确的精度,比如单价*数量=总价之类的计算,那么得用到BigDecimal. 初始化 如下: BigDecimal amount=new BigDecimal(&qu ...
- 【Beta】发布说明
再次号外!Visual Pytorch第二个版本上线了! 目前的网址在这里(http://114.115.151.39/) 哦 有关上一版本的功能介绍说明请参考博客:Visual Pytorch -- ...
- Oracle之clob字段不能union的问题
原因:由于clob类型字段不能使用group by函数,而union中需要使用group by过滤掉重复纪录: 解决方法:union可以改为union all.
- java性能优化之HashMap,LinkedHashMap,TreeMap读取大量数据效率的比较
很多时候,我们用jdbctemplate或mybatis的时候,为了查询通用,会选择使用map数据结构,因为hashmap本身无序,所以为了保证key的有序性,会采用linkedhashmap.所以我 ...
- pc端常用电脑屏幕 ((响应式PC端媒体查询)电脑屏幕分辨率尺寸大全)
PC端************ 按屏幕宽度大小排序(主流的用橙色标明) 分辨率 比例 | 设备尺寸 1024*500 (8.9寸) 1024*768 (比例4:3 | 10.4寸.12.1寸.1 ...