智慧屏安装APP的最佳实践与跨平台小程序开发的结合
1224
2022-11-24
【Flask】上下文管理
Flask 上下文管理基本流程
当浏览器发送请求到服务器时,在flask内部源码如下
# 第1步,封装session,再次封装请求数据# ctx = RequestContext(self, environ) # self是app对象,environ请求是相关的原始数据# ctx.request = Request(environ)# ctx.session = None# 第2步,将包含了request/session的ctx对象放到"空调" { 1232:{ctx:ctx对象} 1231:{ctx:ctx对象} 1211:{ctx:ctx对象} 1111:{ctx:ctx对象} 1261:{ctx:ctx对象} }#第3步,接着执行视图函数#第4步,请求结束,根据当前线程的唯一标记,将“空调”上的数据移除
有关上下文管理的预备知识
偏函数
import functoolsdef index(a1,a2): return a1 + a2# 原来的调用方式# ret = index(1,23)# print(ret)# 偏函数,帮助开发者自动传递参数new_func = functools.partial(index,666) #传入函数名,和预置另一个参数ret = new_func(1)print(ret)
super关键字
"""class Base(object): def func(self): print('Base.func')class Foo(Base): def func(self): # 方式一:根据mro的顺序执行方法 # super(Foo,self).func() # 方式二:主动执行Base类的方法 # Base.func(self) print('Foo.func')obj = Foo()obj.func()"""####################################class Base(object): def func(self): super(Base, self).func() print('Base.func')class Bar(object): def func(self): print('Bar.func')class Foo(Base,Bar): pass# 示例一obj = Foo()obj.func()print(Foo.__mro__)# 示例二# obj = Base()# obj.func()
面向对象中特殊的方法
class Foo(object): def __init__(self): # self.storage = {} #该句会调用__setattr__方法,但self.storage还没创建,会报错 object.__setattr__(self,'storage',{}) #调用父类方法中的__setattr__方法 def __setattr__(self, key, value): print(key,value,self.storage) obj = Foo()obj.xx = 123 #调用Foo类 __setattr__方法
实现栈结构
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('咸鱼')print(_stack.pop())print(_stack.pop())
local类,开辟内存空间
"""{ 1232:{k:v}}"""try: from greenlet import getcurrent as get_identexcept: from threading import get_ident"""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} else: self.storage[ident][key] = value def __getattr__(self, item): ident = get_ident() if ident in self.storage: return self.storage[ident].get(item)"""#flask 源码部分也有local类class Local(object): __slots__ = ('__storage__', '__ident_func__') def __init__(self): # __storage__ = {1231:{'stack':[]}} object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident) 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__() 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)obj = Local()obj.stack = []obj.stack.append('佳俊')obj.stack.append('咸鱼')print(obj.stack)print(obj.stack.pop())print(obj.stack)
localstack类,帮助维护loacl对象中的列表,成栈结构
import functoolstry: from greenlet import getcurrent as get_identexcept: from threading import get_identclass Local(object): __slots__ = ('__storage__', '__ident_func__') def __init__(self): # __storage__ = {1231:{'stack':[]}} object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident) def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name) def __setattr__(self, name, value): # name=stack # value=[] ident = self.__ident_func__() 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)"""__storage__ = { 12312: {stack:[ctx(session/request) ,]}}"""# 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,value): rv = getattr(self._local, 'stack', None) # self._local.stack =>local.getattr if rv is None: self._local.stack = rv = [] # self._local.stack =>local.setattr rv.append(value) # self._local.stack.append(666) return rv def pop(self): """Removes the topmost item from the stack, will return the old value or `None` if the stack was already empty. """ 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 Noneclass RequestContext(object): def __init__(self): self.request = "xx" self.session = 'oo'_request_ctx_stack = LocalStack()_request_ctx_stack.push(RequestContext())def _lookup_req_object(arg): ctx = _request_ctx_stack-() return getattr(ctx,arg) # ctx.request / ctx.sessionrequest = functools.partial(_lookup_req_object,'request')session = functools.partial(_lookup_req_object,'session')print(request())print(session())
slots用法,限制对象访问变量
class Foo(object): __slots__ = ('name',) #限制类的对象,只能外部调用name变量 def __init__(self): self.name = 'alex' # self.age = 18obj = Foo()print(obj.name)# print(obj.age) #会报错
flask 上下文管理流程
先看一个简单的flask程序
from flask import Flaskapp = Flask(__name__)@app.route('/index')def index(): print("index") return '...' if __name__ == "__main__": app.run()
(1)上下文管理:request 执行app.run()后,会执行app.__call__方法,此时又会调用app.wsgi_app,大致调用流程如下
#第一步 wsgi#第二步ctx = ReuqestContext(session,request) #将请求数据和session封装在ctx对象中ctx.push() #将ctx对象加入到__storage__字典中#第三步LocalStack 把ctx对象添加到local中#第四步Local里存放的数据为字典类型__storage__={ 1321:{stack:[ctx,]}}
(2)上下文管理:session
大致步骤与上下文管理request相同,只有获取session并给session赋值有区别
第一步: wsgi第二步:ctx = ReuqestContext(session=None,request)ctx.push()第三步:LocalStack,把ctx对象添加到local中第四步:Local,为字典中的元素开辟独立空间 __storage__={ 1321:{stack:[ctx,]} }第五步:获取ctx中的session,给session赋值(从cookie中读取数据) =>通过调用 open_session给session赋值
上下文管理总结
请求到来之后wsgi会触发__call__方法,由__call__方法再次调用wsgi_app方法在wsgi_app方法中:
首先将请求相关数据+空session 封装到一个RequestContext对象中,即:ctx。将ctx交给LocalStack对象,再由LocalStack将ctx添加到Local中,Local结构如下:storage = { 1231:{stack:[ctx,] } }根据请求中的cookie中提取名称为sessionid对应的值,对cookie进行解密+反序列化,再次赋值给ctx中的session执行视图函数把session中的数据再次写入到cookie中。将ctx删除
结果返回给用户浏览器断开socket连接
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~