flask 3 上下文管理、threading.local相关、基础知识
作者:互联网
Flask day3 上下文管理、threading.local相关、基础知识
内容回顾
1.Linux命令
cd
vim
mkdir
ls
touch
cat
sed
2.面向对象:特殊方法
obj['x']=123 # 会执行__setitem__方法
obj.x=123 # 会执行setattr方法
obj + 123
3.functools
# 自动传参
from functools import partial
def func(a, b, c):
return a + b + c
v1 = func(10, 20, 3)
print(v1)
new_func = partial(func, 10, 20)
v2 = new_func(3)
print(v2)
4.认识的装饰器?应用场景
应用:
-flask:路由、brfore_request
-django:csrf,缓存,用户登录
5.Flask
- 蓝图
- session原理
今日内容
1.threading.local
作用:为每个线程开辟一块空间进行数据存储
from threading import local
from threading import Thread
from threading import get_ident
import time
# 特殊的对象,让对象之间相互独立
obj = local()
# obj = -1
def task(arg):
# 对象.value = 1/2/3/4/5
print(get_ident())
obj.value = arg
time.sleep(2)
print(obj.value)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
>>>>>>>>
3920
11004
740
9880
7396
13304
10220
10492
7928
6904
自己通过字典创建一个类似于threading.local的东西
1.函数方式
{
3920:{val1:0}
11004:{val1:1}
740:{val1:3}
9880:{}
7396:{}
}
storage = {}
def set(k, v):
ident = get_ident()
if ident in storage:
storage[ident][k] = v
else:
storage[ident] = {k: v}
def get(k):
ident = get_ident()
return storage[ident][k]
def task(arg):
set('val', arg)
print(storage)
time.sleep(2)
v = get('val')
print(v)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
2.面向对象方式
class Local:
def __init__(self):
self.storage = {}
def __setattr__(self, k, v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k: v}
def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]
"""
由于实例化时会自动调用Local中的__init__方法,执行self.storage ={}
而self.storage ={}则会自动执行__setattr__方法
会先获取ident = get_ident()然后走else分支self.storage[ident] = {k: v}!!!此时又有self.storage又会再次执行__setattr__所有会进入死循环
最终报错
"""
obj = Local()
def task(arg):
obj.val = arg
print(obj.storage)
time.sleep(2)
print(obj.val)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
3.面向对象优化
class Local:
def __init__(self):
object.__setattr__(self, 'storage', {})
def __setattr__(self, k, v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k: v}
def __getattr__(self, k):
ident = get_ident()
return self.storage[k][item]
"""
由于实例化时会自动调用Local中的__init__方法,执行self.storage ={}
而self.storage ={}则会自动执行__setattr__方法
会先获取ident = get_ident()然后走else分支self.storage[ident] = {k: v}!!!此时又有self.storage又会再次执行__setattr__所有会进入死循环
最终报错
解决方法,初始化时调用父类object去创建storage的空字典
"""
obj = Local()
def task(arg):
obj.val = arg
print(obj.storage)
time.sleep(2)
print(obj.val)
for i in range(10):
t = Thread(target=task, args=(i,))
t.start()
优于threading.local地方
可以为每个线程(协程)开辟一块空间进行数据存储
try:
from greenlet import getcurrent as get_ident
except Exception:
from threading import get_ident
import time
from threading import Thread
class Local:
def __init__(self):
object.__setattr__(self, 'storage', {})
def __setattr__(self, k, v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k: v}
def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]
2.上下文管理
# 在源码中分析上下文管理
第一阶段:
-将ctx(request,session)放到"空调"上(Local对象)
第二阶段:
-将视图函数导入:request/session
第三阶段:
-请求处理完毕
-获取session并保存到cookie
-将ctx删除
# flask中session是什么时候产生什么时候销毁的
当请求进来时,会将request和session封装成一个RequestContext对象,该对象 通过localstack放入内部的local对象中此时session是None值,接着执行open_session将cookie中值拿来放入session中
最后返回时执行save_session将ctx中的读出来进行序列化写入cookie,最后pop将ctx去除
视图阶段的上下文管理
from flask import Flask, request, session
app = Flask(__name__)
@app.route('/')
def hello_world():
"""
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
def _lookup_req_object(name):
# name = request/session
# top = ctx(request,session)
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
# 从ctx中获取name对象 request/session
return getattr(top, name)
"""
print(request) # LocalProxy.__str__
print(request.method) # LocalProxy.__getattr__(key="method") # 先去ctx中获取request,再去request中获取method
print(request.args) # LocalProxy.__getattr__(key="args") # 先去ctx中获取request,再去request中获取args
session['k1'] = 123 # LocalProxy.__setattr__(key="k1") # 先去ctx中获取session,再去session中给k1设置值
print(session['k1']) # LocalProxy.__getattr__(key="k1") # 先去ctx中获取session,再去session中获取args
"""
class LocalProxy(object):
def __init__(self, local, name=None):
# self.__local = 函数
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)
def __getattr__(self, name):
if name == "__members__":
return dir(self._get_current_object())
# name = method
# obj = self._get_current_object() 去ctx中获取request
# return getattr(obj, name) request.method
return getattr(self._get_current_object(), name)
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__)
"""
return 'hello world'
if __name__ == '__main__':
app.run()
"""
用户请求一旦到来请求:
1.app.__call__=========>def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
其中environ是由wsgi操作完封装好的
2.ctx = self.request_context(environ):RequestContext(self, environ)==========>就是一个团队,内有request和session
-ctx.request = Request(environ) = request
-ctx.session = None
-路由匹配
"""
一个请求的完整流程
问题:flask中共有几个LocalStack和Local对象
都是两个
g是什么
是每一次请求的全局变量,在该次请求结束后销毁,可在before_request中给g赋值,在该次请求后面的操作中可以用该变量去取值
标签:__,ident,flask,request,self,storage,threading,session,local 来源: https://www.cnblogs.com/HinaChan/p/14705039.html