Flask上下文管理源码--亲自解析一下
前戏
偏函数
def index(a,b):
return a+b # 原来的调用方法
# ret=index(1,2)
# print(ret) # 偏函数--帮助开发者自动传递参数
import functools
new_func=functools.partial(index,666)
ret=new_func(1)
print(ret) #结果 667
执行父类方法
class Base(object):
def func(self):
print('Base.func') class Foo(Base):
def func(self):
# 方式一:根据mro的顺序执行对应方法
# super().func()
# 方式二:主动执行Base方法
Base.func(self)
print('Foo.func') obj=Foo()
obj.func()
面向对象中特殊方法
class Foo(object):
def __init__(self):
object.__setattr__(self,'storage',{}) def __setattr__(self, key, value):
print(key,value,self.storage) obj=Foo()
obj.xx=123 # __getattr__和__setattr__:当给对象创建属性时,会自动执行__setattr__方法,可以将 函数__setattr__方法放到__init__中
用列表实现一个栈
class Stack(object):
def __init__(self):
self.data=[] def push(self,val):
self.data.append(val) def pop(self):
return self.data.pop() def top(self):
return self.data[-1] stack=Stack()
stack.push('杜举飞')
stack.push('杜太平')
stack.push('杜晨飞') print(stack.pop())
print(stack.pop()) print(stack.top()) #打印第一个进去的元素
# 打印结果:后打印我,是一个先进后出的
slots
class Foo(object):
__slots__=('name')
def __init__(self):
self.name='alex'
self.age='' obj=Foo()
print(obj.name) # 只打印name为alex
print(obj.age) #只打印age报错!!
# __slots__表示对外公开的属性,若括号中只有name,表示外部只能调用name字段
Threading.local
# 多个线程对同一个值,进行修改,如何给每个线程开辟一个内存?
import threading
import time
v=0
def task(i):
global v
v=i
time.sleep(2)
print(v) for i in range(10):
t=threading.Thread(target=task,args=(i,))
t.start()
# 执行结果:9 9 9 9 9 9 9 9 9 9
多个线程对同一个值进行修改
# 给每一个线程开辟一块内存
import threading
import time
from threading import local obj=local() def task(i):
obj.xxxxx=i
time.sleep(2)
print(obj.xxxxx,i) for i in range(10):
t=threading.Thread(target=task,args=(i,))
t.start() # 执行结果:
# 0 0
# 1 1
# 2 2
# 5 5
# ...
# 9 9
Threading.local给每一个线程开辟一块内存
# threading.get_ident()功能和threading.local一样,
# 都是为每个线程开辟一个隔离的内存空间
import time
import threading
'''
{
ident:{'xxxx':i}
}
'''
dic = {}
def task(i):
ident = threading.get_ident()
if ident in dic:
dic[ident]['xxx'] = i
else:
dic[ident] = {'xxx': i}
time.sleep(2)
print(dic[ident]['xxx'], i) for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start()
threading.get_ident()也可以给每个线程开辟一块内存空间,效果和local一样
# 为协程开辟一个隔离的内存空间
import time
import threading
import greenlet
'''
{
ident:{'xxxx':i}
}
'''
dic = {}
def task(i):
ident = greenlet.getcurrent()
if ident in dic:
dic[ident]['xxx'] = i
else:
dic[ident] = {'xxx': i}
time.sleep(2)
print(dic[ident]['xxx'], i) for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start()
为协程开辟一个隔离的内存空间
Local
Local主要帮我们给线程/协程开辟一块内存空间
try:
from greenlet import getcurrent as get_ident # 创建协程的唯一标识
except:
from threading import get_ident # 创建线程的唯一标识 # self.storage 为{ } # self.storage添加完内容后为 {23334:{'alex':12}} class Local(object):
def __init__(self):
object.__setattr__(self, 'storage', {}) def __setattr__(self, key, value):
ident = get_ident()
if ident not in self.storage: # 如果线程的唯一表示不再字典中
self.storage[ident] = {key: value} # 则在{ }创建一个字典 {23423:"alex":123}
else:
self.storage[ident][key] = value def __getattr__(self, item):
ident = get_ident()
if ident in self.storage:
return self.storage[ident].get(item) # item表示alex # 创建一个字典,线程/协程的唯一标识为键,小字典为值! {22234:{'alex':12}}
自己写的Local
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) #self.__ident_func__() 相当于slef.get_ident() def __getattr__(self, name):
try:
print('---执行getattr------')
return self.__storage__[self.__ident_func__()][name] except KeyError:
raise AttributeError(name) def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
print("-----执行setattr----")
try:
# ident=22344 name=age value=12 即:{22344:{'alex':12}}
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) obj=Local()
obj.age=12 #设置属性时,自动调用__setattr__方法,print(obj.age) 时自动调用__getattr__方法
print(obj.age) # # 结果:
# -----set----
# ---get------
#
源码中的Local
LocalStack
由于Local给我们的线程/协程开辟好了内存空间,当往里边存取数据时使用append、pop存取少麻烦,于是有了LocalStack;
LocalStack帮助我们在给线程/协程开辟的内存空间中,将列表维护成一个栈。
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident import functools
class Local(object):
__slots__ = ('__storage__', '__ident_func__') def __init__(self):
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__ident_func__', get_ident) # self.__ident_func__() 相当于slef.get_ident() def __getattr__(self, name):
try:
print('---执行getattr------')
return self.__storage__[self.__ident_func__()][name] except KeyError:
raise AttributeError(name) def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
print("-----执行setattr----")
try:
# ident=22344 name=age value=12 即:{22344:{'alex':12}}
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为线程开辟了一个内存空间后,往内存空间中放数据时,可以使用append,但是比较麻烦,源码帮我们提供了方法,即LocalStack这个类
# LocalStack帮我们将列表维护成一个栈
# 往线程的栈中存放数据--自己写
'''
__storage__={
123121:{ ''stack:[] }
}
'''
# obj = Local()
# obj.stack = []
# obj.stack.append('老杜')
# obj.stack.append('小杜')
# print(obj.stack)
# print(obj.stack.pop())
# print(obj.stack) # 往线程的栈中存放数据--源码提供的
class LocalStack(object):
def __init__(self):
self._local=Local() def push(self, obj):
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:
return stack[-1]
else:
return stack.pop() def top(self):
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None xxx=LocalStack() class RequestContext(object):
def __init__(self):
self.request='xx'
self.session='oo'
ctx=RequestContext()
xxx.push(ctx)
'''
__storage__={
12312:{stack:[ctx(session/request),]}
}
'''
def get_request_or_session(arg):
ctx=xxx.top()
return getattr(ctx,arg) request=functools.partial(get_request_or_session,'request')
session=functools.partial(get_request_or_session,'session') print(request())
print(session())
自己写的LocalStack
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident import functools
class Local(object):
__slots__ = ('__storage__', '__ident_func__') def __init__(self):
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__ident_func__', get_ident) # self.__ident_func__() 相当于slef.get_ident() def __getattr__(self, name):
try:
print('---执行getattr------')
return self.__storage__[self.__ident_func__()][name] except KeyError:
raise AttributeError(name) def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
print("-----执行setattr----")
try:
# ident=22344 name=age value=12 即:{22344:{'alex':12}}
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为线程开辟了一个内存空间后,往内存空间中放数据时,可以使用append,但是比较麻烦,源码帮我们提供了方法,即LocalStack这个类
# LocalStack帮我们将列表维护成一个栈
# 往线程的栈中存放数据--自己写
'''
__storage__={
123121:{ ''stack:[] }
}
'''
# obj = Local()
# obj.stack = []
# obj.stack.append('老杜')
# obj.stack.append('小杜')
# print(obj.stack)
# print(obj.stack.pop())
# print(obj.stack) # 往线程的栈中存放数据--源码提供的
class LocalStack(object):
def __init__(self):
self._local=Local() def push(self, obj):
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:
return stack[-1]
else:
return stack.pop() def top(self):
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None _request_ctx_stack=LocalStack() # RequestContext类帮我们往键为 stack的字典存值
class RequestContext(object):
def __init__(self):
self.request='xx'
self.session='oo'
ctx=RequestContext()
_request_ctx_stack.push(ctx)
'''
__storage__={
12312:{stack:[ctx(session/request),]}
}
''' # _lookup_req_object 帮我们取出以stack为键的值
def _lookup_req_object(arg):
ctx=_request_ctx_stack.top()
return getattr(ctx,arg) request=functools.partial(_lookup_req_object,'request')
session=functools.partial(_lookup_req_object,'session') print(request())
print(session())
源码中的LocalStack
Flask上下文管理源码
上下文request请求
请求到来时:
#将request、session放到ctx中
ctx=RequestContext(self,environ)
ctx.request=Request(environ)
ctx.session=None 将包含了request、session的ctx对象放到‘箱子’中
{
12312: {ctx:ctx对象}
12232: {ctx:ctx对象}
11232: {ctx:ctx对象}
13542: {ctx:ctx对象}
}
执行视图函数: from flask import request,session
#request.method不是执行了request中的method方法,而是代表执行一个线程
#12312:{ctx:ctx对象}中的 ctx对象的request方法,request中的method方法
request.method 请求结束:
根据当前线程的唯一标识,将‘箱子’上的数据移除
大框架
上下文管理 request
a.温大夜:wsgi
b.鞠腾 :
ctx=RequestContext(session,request)
ctx.push() c.马玲:
LocalStack,把ctx对象添加到Local中 d.空调:Local
__storage__={
12312:{stack:[stx,]}
}
#请求来了,执行wsgi(温大爷处报道),接着R
上下文管理 request框架
上下文管理 request a.温大夜:wsgi 代码体现: 开始flask程序
执行run.app()方法
---->执行__call__方法
---->执行wsgi_app()方法 b.鞠腾 :
ctx=RequestContext(session,request) #鞠腾将水装满杯子
ctx.push() b代码流程.
---->在wsgi_app方法中执行self.request_context(environ)
----->执行wsgi_app()方法,返回RequestContext(self, environ)
将session和request方法放到RequestContext中
----->接着执行ctx.push() c.马玲:
LocalStack,把ctx对象添加到Local中 #马玲把杯子放到空调上 c代码流程
--->push()方法中执行_request_ctx_stack.push(self) #self为ctx对象
--->由于_request_ctx_stack = LocalStack()
--->在LocalStack的__init__方法中self._local = Local()
---->Local()类中执行__init__方法中的__setattr__、__getattr__方法 d.空调:Local
__storage__={
12312:{stack:[ctx,]}
}
上下文管理 request框架解释-轻松版代码流程
图解上下文管理request请求
flask-session
当用户请求发来时,flask-session流程和上边的上下文request流程差不多。唯一的不同,在最后多了一个步骤,(黑哥)从LocalStack处取到ctx中的空session,给session赋值(从浏览器的cookie处取到session,采用RedisSessionInterface中的open_session()找到session),然后通过save_session()将session保存在redis中。
from flask_session import RedisSessionInterface #查看flask_session源码
from flask import Flask,session,request
import redis
from flask_session import Session app=Flask(__name__) # 将session存入redis中的配置操作,就这三行,源码在RedisSessionInterface中,将session保存到
# 原理:a.session保存到redis中 数据结构:session:随机字符串1:sdfsdasdfsd34sfas
# session:随机字符串2:sdfsdasdfsd34sfas
# b.使用uuid生成的随机字符串返回给用户
app.config['SESSION_TYPE']='redis'
app.config['SESSION_REDIS']=redis.Redis(host='140.143.227.206',port=6379,password='')
Session(app) @app.route('/login')
def login():
session['user']='alex'
return 'adsfsaa' @app.route('/index')
def index():
print(session.get('user'))
return '...' if __name__ == '__main__':
app.run()
flask-session
Flask上下文管理源码--亲自解析一下的更多相关文章
- Flask上下文管理源码分析
上下文管理本质(类似于threading.local): 1.每一个线程都会在Local类中创建一条数据: { "唯一标识":{stark:[ctx,]}, "唯一标识& ...
- Flask上下文管理源码分析 ——(3)
引出的问题 Flask如何使用上下文临时把某些对象变为全局可访问 首先我们做如下的几种情况的假设 情况一:单进程单线程 这种情况可以基于全局变量存储临时的对象 情况二:单进程多线程 这种情况会出现多个 ...
- Kotlin系列之序列(Sequences)源码完全解析
Kotlin系列之序列(Sequences)源码完全解析 2018年06月05日 22:04:50 mikyou 阅读数:179 标签: Kotlin序列(sequence)源码解析Androidja ...
- java动态代理源码解析
众所周知,java动态代理同反射原理一直是许多框架的底层实现,之前一直没有时间来分析动态代理的底层源码,现结合源码分析一下动态代理的底层实现 类和接口 java动态代理的主要类和接口有:java.la ...
- java 1.8 动态代理源码分析
JDK8动态代理源码分析 动态代理的基本使用就不详细介绍了: 例子: class proxyed implements pro{ @Override public void text() { Syst ...
- Flask系列之源码分析(一)
目录: 涉及知识点 Flask框架原理 简单示例 路由系统原理源码分析 请求流程简单源码分析 响应流程简单源码分析 session简单源码分析 涉及知识点 1.装饰器 闭包思想 def wapper( ...
- Flask框架(二)—— 反向解析、配置信息、路由系统、模板、请求响应、闪现、session
Flask框架(二)—— 反向解析.配置信息.路由系统.模板.请求响应.闪现.session 目录 反向解析.配置信息.路由系统.模板.请求响应.闪现.session 一.反向解析 1.什么是反向解析 ...
- spring5 源码深度解析----- AOP代理的生成
在获取了所有对应bean的增强后,便可以进行代理的创建了.回到AbstractAutoProxyCreator的wrapIfNecessary方法中,如下所示: protected static fi ...
- iOS开发之Masonry框架源码深度解析
Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...
随机推荐
- Word写博常用博客URL地址
地址 描述 http://imguowei.blog.51cto.com/xmlrpc.php 51cto http://upload.move.blog.sina.com.cn/blog_rebui ...
- ABP中的拦截器之EntityHistoryInterceptor
今天我们接着之前的系列接着来写另外一种拦截器EntityHistoryInterceptor,这个拦截器到底是做什么的呢?这个从字面上理解是实体历史?这个到底是什么意思?带着这个问题我们来一步步去分析 ...
- C# 数组、HashSet等内存耗尽的解决办法
在C#中,如果数据量太大,就会出现 'System.OutOfMemoryException' 异常. 解决办法来自于Stack Overflow和MSDN https://docs.micro ...
- kNN总结
1,kNN不训练模型 2,主要是通过计算 3,计算点到每个近邻的距离,按照距离递增排序,选取距离最近的k个邻居,在k个邻居中出现频率最大的就是它的分类结果 4,计算距离有不同的距离公式,可以看每种公式 ...
- 「CF1154F」Shovels Shop【背包DP】
题目链接 [洛谷传送门] 题解 非常简单的背包. \(f[i]\)表示购买\(i\)个物品所需要最少的花费. 不考虑免费的限制条件,那么一定是选择前\(k\)个双鞋子. 那么加入免费的条件,那么还是要 ...
- CF993D Compute Power(二分+Dp)
一看到这种求\(min/max\left \{ \frac{\sum a_i}{\sum b_i} \right \}\)的题肯定是\(01\)分数规划,大概可以算作一种二分? 设\(ans\)为当前 ...
- MessageFormat的用法,java动态替换String字符串中的占位符
import java.text.MessageFormat; import java.util.GregorianCalendar; import java.util.Locale; public ...
- 使用C语言中qsort()函数对浮点型数组无法成功排序的问题
一 写在开头 1.1 本节内容 本节主要内容是有关C语言中qsort()函数的探讨. 二 问题和相应解决方法 qsort()是C标准库中的一个通用的排序函数.它既能对整型数据进行排序也能对浮点型数据进 ...
- [Android] Android GreenDao 保存 JavaBean 或者List <JavaBean>类型数据
Android GreenDao 保存 JavaBean 或者List <JavaBean>类型数据 简介 数据库存储数据基本上每个APP都有用到,GreenDAO 是一个将对象映射到 S ...
- UML建工工具
本篇博文简单介绍一下自己在搜索UML建模工具的过程中收集到的一些信息. 如果想用中文的,可以考虑楚凡科技的Trufun Plato,不过最近好像没有怎么更新了. 很多前辈以前用的是Rational R ...