flask中Localstack和Local对象实现(flask请求封装的实现)
1.源码分析:Local()对象和LocalStack()对象()
from flask import globals 点击去globals,可以看到from werkzeug.local import LocalStack, LocalProxy 是通过werkzeug的local实现的flask的local。
源码: try: from greenlet import getcurrent as get_ident # 注意这是导入的协程的get_ident,说明flask的控制力度更细,也是更牛逼的地方 # 我们可以为线程开辟空间,flask可以为协程开辟空间 except ImportError: try: from thread import get_ident except ImportError: from _thread import get_ident class Local(object): 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 __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__() # 1111 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)
关于flask里面的local()对象,和在上一篇自定义版普通的threading.local方法的是逻辑一样的. 在Local()对象里面__storage__的格式如下: __storage__= { ident(表示线程的唯一id):{name:value} } 但是这里牛逼的是LocalStack类。在globals里面有着两个实例化 _request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() 先记住这两个实例化的名字。来看LocalStack类里面有什么牛逼的地方
class LocalStack(object): def __init__(self): self._local = Local() def push(self, obj): """Pushes a new item to the stack""" # self._local.stack == getattr # rv = None rv = getattr(self._local, "stack", None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rv def pop(self): stack = getattr(self._local, "stack", None) if stack is None: return None elif len(stack) == 1: # 在只有一个值的时候,就销毁,先返回最后一个值,在销毁,存成[],在release_local()里面实现 # release_local(self._local) # del __storage__[1111] return stack[-1] else: return stack.pop() @property def top(self): try: return self._local.stack[-1] except (AttributeError, IndexError): return None obj = LocalStack() obj.push('kobe') print(obj.top) obj.pop() 第一步: obj = LocalStack()实力化的时候,会去执行__init__方法 LocalStack的__init__中 实例化了Local(),并赋值给self._local 第二步: 在执行obj.push('kobe')的时候,执行了rv = getattr(self._local, "stack", None) 其中的getattr执行的是self._local的getattr方法,也就是执行self._local.stack。 注意:这一步是通过self._local的getattr方法在获取值。 因为此时Local里面的getattr方法是没有值的,所以返回一个None,所以rv=None 第三步: 继续向下执行self._local.stack = rv = [],此时self._local.stack和rv都指向这个[]的内存地址 这句话可以拆分成self._local.stack = rv,此时是去执行self._local.setattr方法 self._local.setattr的name= stack,value等于[] 所以在执行到这步骤的时候,self._local里面的storage是如下格式 storage = { ident(理解成线程唯一id):{"stack":[]} } 第四步: 执行rv.append(obj),相当于在storage里面添加了kobe storage = { ident(理解成线程唯一id):{"stack":["kobe",]} } 所以说白了,执行push方法的时候,会自动的在self._local.storage里面添加数据 这里面只有push逻辑比较麻烦,top和pop的原理比较简单.
Local()和LocalStack总结:
在flask中有个local类,他和上一篇的自定义的threading.local的功能一样,为每个线程开辟空间进行存取数据,他们两个的内部实现机制相同,内部维护一个字典,以线程(协程)ID为key,进行数据隔离,如: __storage__ = { 1211:{'k1':123} } obj = Local() obj.k1 = 123 在flask中还有一个LocalStack的类,他内部会依赖local对象,local对象负责存储数据,localstack对象用于将local中的值维护成一个栈。 __storage__ = { 1211:{'stack':['k1',]} } obj= LocalStack() obj.push('k1') obj.top obj.pop()
在flask里面真正使用的都是LocalStack()对象,并没有Local()对象
2.flask中Local()和LocalStack()对象的具体作用
_request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() 还记得上面的这两个类嘛?? 在flask源码内部里面使用了单例模式,创建了两个LocalStack()对象分别赋值,并且只实力化了这两个LocalStack()对象 _request_ctx_stack 其中_request_ctx_stack的__storage__里面维护的数据如下: __storage__ = { (线程id)1111:{"stack":[RequestContext(request,session),]} } RequestContext指的是一个对象,里面存放请求信息request和session信息 _app_ctx_stack 其中_app_ctx_stack的__storage__里面维护的数据如下: __storage__ = { (线程id)1111:{"stack":[AppContext对象(app,g),]} } AppContext指的也是一个对象,里面存放app对象和g信息,app指的就是实例化的时候的那个app信息(里面包含了好多信息,路由,配置文件等) 总结: flask的请求进来之后,会将所有的信息存成两个对象 RequestContext对象:存放request请求和session信息,最后存在_request_ctx_stack中 AppContext对象:存放app对象和g(一般是空字典)信息,最后存在_app_ctx_stack中 所以flask有两个上下文管理:请求上下文管理(RequestContext)和应用上下文管理(AppContext),合在一起叫做flask的上下文管理
3.总结
那么上面的流程到底在flask中做了什么事情?
上面的流程就是flask中请求过来之后封装数据的过程。
那么Local和Localstack()对象在请求封装是做了什么?
Local()对象:和threading.local的功能一样,为每一个即将到来的请求,也就是线程,开辟自己的空间,用于保存该线程的一些数据,进行数据隔离
LocalStack(): 基于Local对象,将Local对象中每一个线程的数据改成栈的形式来存储,用于添加返回和删除信息。
flask和Django的有一个最重要的区别就是:
Django的请求是一层一层的封装的,都放在django的缓存里面
Flask的请求是基于上下文管理来做。
flask中请求过来之后的封装流程图:

1.当请求进来之后,将请求分成两个对象
一个是RequestContext对象:request对象和session
一个是AppContext对象:app对象和g(空字典)
2.将对象存放到上下文管理里面,具体步骤如下
2.1 实例化LocalStack的两个类
_request_ctx_stack = LocalStack() # 用于存放RequestContext对象的信息
_app_ctx_stack = LocalStack() # 用于存放AppContext对象的信息
2.2 flask实现了两个Local()对象和LocalStack()对象,其中:
Local()对象:实现了魏每一个线程开辟空间,存储数据,保证数据隔离
LocalStack()对象:基于Local对象,将保存现成数据的格式变成栈的格式,方便以后增加,取值,和删除信息
2.3 其中存储的数据格式如下:
_request_ctx_stack的__storage__里面维护的数据如下:
__storage__ = {
(线程id)1111:{"stack":[RequestContext(request,session),]}
}
_app_ctx_stack的__storage__里面维护的数据如下:
__storage__ = {
(线程id)1111:{"stack":[AppContext对象(app,g),]}
}
2.4 封装好之后,后端就可以调用了
pass
上帝说要有光,于是便有了光;上帝说要有女人,于是便有了女人!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类