flask 请求上下文
一篇引用大牛的 https://www.cnblogs.com/zhaopanpan/p/9457343.html
### 线程安全 ```python# 线程不安全class Foo(object): pass foo = Foo()foo.num = 1 import timeimport threading def my_num(i): foo.num = i time.sleep(1) print(foo.num,threading.current_thread().ident) for i in range(20): th = threading.Thread(target=my_num,args=(i,)) th.start()---------------------------------------------------------------------------- # 线程安全from threading import localclass Foo(local): pass foo = Foo()foo.num = 1 import timeimport threading def my_num(i): foo.num = i time.sleep(1) print(foo.num,threading.current_thread().ident) for i in range(200000): th = threading.Thread(target=my_num,args=(i,)) th.start() # 开辟新空间 - 浪费了部分资源 - 速度保证 - 保证安全"""{ 16232:[request],# 123 17164:[request],# 456 9088: [request],# 567 16084:[request],# 789} Threading.localFlask 上下文机制就是使用的 Threading.local线程进来 开辟一个空间给这个线程,线程操作的所有任务,都会复制一份儿到空间中"""``` ### 栈 Stack ```python# Stackclass MyStack(object): data = [] def __setattr__(self, key, value): self.push(key,value) def push(self,key,value): self.data.append({key:value}) def top(self): return self.data.pop() my_stack = MyStack() my_stack.name = 666 # [{name:666}]my_stack.name = 777 # [{name:666},{name:777}] print(my_stack.data) # my_stack.push(666)# my_stack.push(777)# my_stack.push(888)## print(my_stack.top(),my_stack.data)# print(my_stack.top(),my_stack.data)# print(my_stack.top(),my_stack.data)``` ### 局部的栈 LocalStack ```python# LocalStack 安全的 栈from threading import get_ident # 获取当前线程的 idimport threading class MyLocalStack(object): storage={} def push(self,item): try: self.storage[get_ident()].append(item) except: self.storage[get_ident()]=[item] def top(self): return self.storage[get_ident()].pop() my_local_stack = MyLocalStack() import timedef go(i): my_local_stack.push(i) time.sleep(1) # my_local_stack.top() for i in range(5): th = threading.Thread(target=go,args=(i,)) th.start() print(my_local_stack.storage)``` ## flask 的 请求上下文 + ## werkzeug + flask 的 wsgi ```pythonfrom werkzeug.wrappers import Request,Responsefrom werkzeug.serving import run_simple @Request.applicationdef app(environ): print(environ) return Response("200OK") run_simple("0.0.0.0",9527,app) ``` ```pythonfrom flask import Flaskapp = Flask(__name__) if __name__ == '__main__': app.run(host='0.0.0.0',port=7088) app.__call__ app.wsgi_app ``` ### 上文 1. 从 **`run()`** 开始 + 进入源码 其中的 >> `self = app = Flask()` + 导入了 `from werkzeug.serving import run_simple` 执行了 `run_simple(host, port, self, **options)` 方法 + 看这一句 `run_simple("0.0.0.0",9527, app) ` 也就是说 self 会执行 >> `self = app = Flask() = self()` + 也就 == app() 对象() 执行 类的 `__call__()` 方法 2. `__call__() ` 执行了 `self.wsgi_app(environ, start_redponse)` **environ = request 原始信息** 3. 进入 `app.wsgi_app` + `def wsgi_app(self, environ, start_response):` >> self = app = Flask() + self 执行了这个方法 `ctx = self.request_context(environ)` 方法中执行了 一个类 `RequestContext(self, environ)` ctx.py文件中 >> 这个对象中 包含了 两个 值 requset/session ctx = requsetcontext --> requset/session + 在这个类中 的 初始化方法 中 `def __init__(self, app, environ, request=None):` >> self = RequestContext ->request/session app = Flask request=None 执行方法 `request = app.request_class(environ)` 这个方法将 environ 序列化 出了 request对象 就是可以使用 request.method requset.form ... 方法 了 + 执行ctx.push() 方法 4. ctx.push() 方法 + 方法中执行了 `top = _request_ctx_stack.top` --> `_request_ctx_stack = LocalStack()` 实例化时的 `__init__` 方法中 初始化了 两个 对象 >> `self._local = {"__storage__": {}, "__ident_func__": get_ident}` >`get_ident` 获取线程 或携程的 id 并没有执行 + `_request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` + `.top ` 方法 执行了 `self._local.stact[-1]` .stack 调用 Local(object): 对象的 `__getattr__(self) 方法` + 方法中 调用 `self.__storage__[self.__ident_func__()][name]` 也就是从 `{"__storage__": {}, "__ident_func__": get_ident}` 中的 `__storage__` 中通过key 取值 此时 `__storage__` 中为 空字典 报错 抛出异常 `AttributeError(name)` 这个异常在上面的 top 方法中 被捕获 返回 一个 None 返回 **top = None** 之后的 if 判断不成立 + 之后又执行了 `_request_ctx_stack.push(self)` 代码 其中的 ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` + 执行了.push(self) 方法 这个self = ctx = requset/session 进入 push() 方法 + `def push(self, obj)`这里面的 self 是 ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` obj = ctx = requset/session 执行 : ` rv = getattr(self._local, 'stack', None)` `self._local = {"__storage__": {}, "__ident_func__": get_ident}` rv = None -> if判断 执行` self._local.stack = rv = [] rv.append(obj) ` 走对象的 `__setattr__(self,name,value)`方法 返回 =>> `{"__storage__": {7088:{"stack": rv=[] }}, "__ident_func__": get_ident}` + 返回 rv.append(obj) ==>`{"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}` `rv=[ctx=>request/session] ` 并没有接收返回值 执行完之后 `self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}` ### 下文 + 使用时才执行 ```python @app.route("/") def login(): if requset.method =='POST': ... # requset.method 之后启动下文 ``` + 进入 request ```python # partial 偏函数 request = LocalProxy( partial( _lookup_req_object, 'request' ) ) ``` + `_lookup_req_object` ```python def _lookup_req_object(name): top = _request_ctx_stack.top # _request_ctx_stack = self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident} 调用.top 方法 if top is None: raise RuntimeError(_request_ctx_err_msg) return getattr(top, name) ``` + .top 中 执行了 `self._local.stack[-1]` ```python # 执行 self._local的 __getattr__ 方法 def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name) # 返回了 [ctx => request / session ] ``` 执行 [-1] 得到 `ctx => request / session` + `top = ctx => request / session` + `getattr(top, name)` name = request 从偏函数传递过来的 方法 得到了 一个 request 对象 及 request 的真身 + 查看` LocalProxy(偏函数没被执行的 )` 实例化 执行`def __init__(self, local, name=None):` local = request 的偏函数 ```python def __init__(self, local, name=None): object.__setattr__(self, '_LocalProxy__local', local) object.__setattr__(self, '__name__', name) if callable(local) and not hasattr(local, '__release_local__'): # "local" is a callable that is not an instance of Local or # LocalManager: mark it as a wrapped function. object.__setattr__(self, '__wrapped__', local) ``` + request.method 执行 .方法 调用 `__getattr__()` 执行 `getattr(self._get_current_object(), name)` ```python def _get_current_object(self): if not hasattr(self.__local, '__release_local__'): return self.__local() try: return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError('no object bound to %s' % self.__name__) ``` `__local = local = requset偏函数执行 = requset` + `getattr(request, name)` name = method + ### 查看 LocalProxy 类 包含了 所有面向对象的 特殊方法 ### 应用上下文 + 会在 离线脚本 的时候使用 + 从 `app.wsgi_app` 中 找到 `ctx.push()` 的方法 + `app_ctx = _app_ctx_stack.top` 这个 就是应用上下文 ```python app_ctx = _app_ctx_stack.top 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) ``` 1. `_app_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` 2. `.top` 方法 返回的还是 None 3. `app_ctx = None` + `app_ctx = self.app.app_context()` 序列化 app 得到 AppContext(app,g) -> requestcontext(request/session) + `app_ctx.push()` 得到 `self._local = {"__storage__": {7088:{"stack": [app_ctx(app, g)] }}, "__ident_func__": get_ident}` g会在 离线脚本 的时候使用 `current_app = LocalProxy(_find_app)` = app = Flask() ```pythondef _find_app(): top = _app_ctx_stack.top # 拿到 app_ctx(app,g) if top is None: raise RuntimeError(_app_ctx_err_msg) return top.app # 返回一个 app 独立的 app ``` 请求结束之后执行 pop 方法 删除缓存 `g = LocalProxy(partial(_lookup_app_object, 'g'))`
转载于:https://www.cnblogs.com/zhangchen-sx/p/10588088.html
flask 请求上下文相关推荐
- python Flask 10 Flask请求上下文管理werkzeug
什么是上下文 上下文相当于一个容器,保存了 Flask 程序运行过程中的一些信息. Flask 中有两种上下文,请求上下文(request 和 session )和应用上下文(current_a ...
- flask 核心 之 应用上下文 及 请求上下文
Werkzeugs 是 Flask 的底层WSGI库. 什么是WSGI? 一段简单的app: def dispath_request(self, request):return Response('H ...
- Web框架——Flask系列之请求上下文与应用上下文请求钩子Flask-Script扩展命令行(十七)
一.请求上下文和应用上下文 请求上下文(request context) request和session都属于请求上下文对象. 应用上下文(application context) current_a ...
- flask中的请求上下文
2019独角兽企业重金招聘Python工程师标准>>> 根据前一篇应用上下文可知,请求上下文的作用域是发生在请求到来之后. 如有一个应用函数返回用户应该跳转到的URL.想象它总是会跳 ...
- Flask的上下文管理机制
前引 在了解flask上下文管理机制之前,先来一波必知必会的知识点. 面向对象双下方法 首先,先来聊一聊面向对象中的一些特殊的双下划线方法,比如__call__.__getattr__系列.__get ...
- flask的上下文的机理与应用(转载+整理)
请求上下文面向开发者使用的对象主要是request和session: 应用上下文面向开发者使用的对象主要是current_app和g; #------------------------------- ...
- Flask框架——上下文、flask_script扩展
目录 上下文(引用池,引用区) flask_script扩展 上下文(引用池,引用区) 上下文:相当于一个容器,保存了 Flask 程序运行过程中的一些信息. 为了避免大量可有可无的参数把视图函数弄得 ...
- fragment怎么获得上下文环境_Flask 源码剖析 (三):Flask 的上下文机制 (上)
写文章其实很费力,你的「在看」很重要. 前言 在面试 Python web 方面的工作时,如果你说自己阅读过 Flask 源码,那么 Flask 上下文机制的实现原理肯定会被问到,本篇文章就来剖析一下 ...
- Flask 应用上下文
上下文管理 threading.local 请求上下文:RequstContext request session 应用上下文:AppContext app(current_app) g 1.请求到来 ...
- 应用上下文请求上下文
用过 Flask 做 Web 开发的同学应该不会不记得 App Context 和 Request Context 这两个名字--这两个 Context 算是 Flask 中比较特色的设计.[1] 从 ...
最新文章
- JavaScript学习笔记—— 4. 变量、作用域和内存问题
- 如何让网站被百度谷歌快速收录
- 安装两个硬盘时应如何跳线?
- 工作总结3:axios里面的主要参数
- svg入门经典pdf_机器学习最好的入门课程是什么?
- Spring MVC中的基本流程
- java工程开发之图形化界面之(第六课)
- Early Z Culling 优化
- strace监视系统调用
- nginx启动只有master没有worker_深入探索Nginx工作原理
- Macro版Property Generator辅助工具
- Java 的运行机制
- Momentum, RMSprob and Adam
- 微信小程序动画效果集合
- 解决网页文字不能复制,复制网页文字的方法
- html在浏览器中的渲染原理,浏览器渲染原理
- 字节跳动、阿里等大厂的真实工作体验如何?看看四位程序员的自述
- 谷歌外链建设2022年如何判断和购买google优质外链
- 晒晒老衲用的WordPress插件
- L1-057 PTA使我精神焕发 (5 分) 天梯赛 详解
热门文章
- [UWP]了解模板化控件(8):ItemsControl
- Cloud Container Service experimentation
- linux 查看分区
- 让ProgressPar动起来
- “NLP的那些事儿”开张了!
- linux安装好的mysql rpm -qa |grep mysql不见
- Spring时间(Date)类型转换+自定义
- BUG Error:Execution failed for task ':app:dexDebug'.
- Java 中判断char 是否为空格 和空
- 模式窗口(Window.ShowModalDialogs)中提交不弹出新窗口