|
深度刨析flask底层调用机制
# 请求上文
1、 from flask import Flask
app=Flask(__name__)
app.run() 是入口
def run(self) self是app
...
from werkzeug.serving import run_simple
2、run_simple(host,post,self) self是app并且调用app的__call__方法
def __call__(self,environ,start_response) self是app
return self.wsgi_app(environ,start_response)
3、self.wsgi_app(environ,start_response)
def wsgi_app(self,environ,start_response) self是app对象
ctx = self.request_context(environ)
def request_context(self,environ) self是app对象
return ReqeustContext(self,environ)
4、ReqeustContext(self,environ) 类实例化会调用RC对象__init__,self(app)当作参数传入到里面,
class RequestContext:
def __init__(self,app,environ,request=None,session=None):self为RC对象,app是传进的self
self.app=app
request=app.request_class(environ) # 将原始请求变成flask.request
self.request=reqeust # 给RC对象添加request属性
self.session=session # 当前session为None
5、ctx=RC对象<request(flask形式的属性),session>
6、ctx.push #ctx是RC对象
def push(self) # self是ctx对象
top=_request_ctx_stack.top
在global.py中可以看到 _request_ctx_stack=LocalStack() 会调用LocalStack的__init__方法
class LocalStack:
def __init__(self): # self是LocalStack
self._local=Local()
class Local()
__slots__=("storage","ident_func__") # 当前插槽限定只能有这两个属性
def __init__(self):
object.setattr(self,'__storage__',{})
object.setattr(self,'__ident_func__',get_ident) get_ident from greenlet import getcurrent as get_ident
7、_request_ctx_stack
_request_ctx_stack=LocalStack={
_local:{
__storage__:{}
__ident_func__:get_ident 一旦执行就会是int的线程数字
}
8、top=_request_ctx_stack.top = _request_ctx_stack=LocalStack={ _local:{
__storage__:{}
__ident_func__:get_ident 一旦执行就会是int的线程数字
}
}.top
LocalStack.top 推断三种可能,property方法,属性,__getattr__方法,优先级一次从左到右
@property
def top(self) self是LocalStack对象
try:
return self._local.stack[-1] # _local对象下面没有属性,推断有两种可能,property,__getattr__
没有找到property方法,那就执行__getattr__方法,_local对象的__getattr__
def __getattr__(self,name) self是_local对象,name是.stack当作键
try:
return self.__storage__[self.__ident_func__()][name] 通过空字典中括号取值,没有这个key就是报keyError
except KeyError:
raise AttributeError(name)
top=_request_ctx_stack.top的返回值是AttributeError(error)
except(AttributeError,IndexError):
return None
top=_request_ctx_stack.top的返回值为空
9、_request_ctx_stack.push(self) self是ctx=RC对象,当作参数传进去
def push(self,obj) # 此时self是_request_ctx_stack对象,obj是传进来的self也就是ctx<request和session>
rv=getattr(self._local,"stack",None)
_local:{
__storage__:{}
__ident_func__:get_ident 一旦执行就会是int的线程数字
}
取不到stack属性或者方法,返回值还是None
if rv is None:
self._local.stack=rv=[] 因为_local对象里面限制类属性,所以.stack=rv=[]的时候出走_local的__setattr__属性
class Local():
def __setattr__(self) self是Local对象
ident=self.__ident_func__() # 得到线程id 9527
storage=self.__storage__ # 得到空字典 {}
try:
storage[ident][name]=value # 这个通过索引取值的时候就会报错KeyError执行到下面
except KeyError:
storage[ident]={name:value}# { 9527:{stack:[]} }
rv.append(obj) 就是在[CTX<request,session>]
return rv
10、此时的经过ctx.push后
global.py中的公共变量随之发生变化了:
从之前的__storage__:{} ——>{9527:{stack:[CTX<request,session>]}}
_request_ctx_stack=LocalStack={ _local:{
__storage__:{9527:{stack:[CTX<request,session>]}}
__ident_func__:get_ident 一旦执行就会是int的线程数字
}
}
# 请求下文
1、request=LocalProxy(partial(_lookup_req_object,"request"))
def _lookup_req_object("name"): # name=”request“
top=_request_ctx_stack.top # 执行top的property方法
_request_ctx_stack=LocalStack={
_local:{
__storage__:{9527:{stack:[CTX<request,session>]}}
__ident_func__:get_ident 一旦执行就会是int的线程数字
}
}
class LocalStack:
@property
def top(self): # self就是LocalStack对象
try:
return self._local.stack[-1] # _local.stack实际执行_local对象的__getattr__方法,因为_local没有stack属性被限制了插槽
def __getattr__(self,name) # 此时的self是_local对象
try:
return self.__storage__[self.__ident_func__()][name] 这里面的运行结果是[CTX<request,session>]
这个return self._local.stack[-1] 的结果就是CTX<request,session>对象
top=_request_ctx_stack.top 运行结果就是CTX<request,session>对象
return getattr(top,'name') # 从CTX<request,session>中反射到"request"属性,request就是处理后的Flask.request
2、request=LocalProxy(partial(_lookup_req_object,"request")) ——>request=LocalProxy(newPartial)可以知道NewPartial就是函数的变形
request=LocalProxy(newPartial) # 执行LocalProxy对象的__init__方法
class LocalProxy:
__slots__("__local","__dict__","__name__","__wrapped__")
def __init__(self,local,name=None):self是LocalProxy对象,local是NewPartial的函数地址没有执行
object.__setattr__(self,"_LocalProxy__local",local) 给类加一个私有属性
object.__setattr__(self,"__name__",name)
if callable(local) and not hasattr(local,"__release_local__") #local是否是可执行对象和local有没有__release_local__属性或者方法
object.__setattr__(self,"__wrapped__",local) # LocalProxy对象里面由一个属性是__wrapped__=local
3、request=LocalProxy(partial(_lookup_req_object,"request"))
我们平常调用的request.method 实际执行里面的LocalProxy对象的__getattr__方法
def __getattr__(self,name) #name就是method
if name =="__members__"
return dir(self._get_current_object())
return getattr(self._get_current_object(),name) #self是LocalProxy对象,_get_current_object()方法
4、def get_current_object(self):# self是LocalProxy对象
if not hasattr(self.__local,"__release_local__"): # 如果偏函数没有__release_local__方法或者属性
return self.__local() # object.__setattr__(self,"_LocalProxy__local",local) 执行偏函数->Flask.request
所以return getattr(self._get_current_object(),name)——>Flask.request对象.method,从request去对应的属性或方法
4、ctx.auto_pop(error) CTX<request,session>对象
def auto_pop(self,error) #self是CTX对象
...
else:
self.pop(exc) #self是CTX对象
def pop(self,exc=_sentinel):
...
finally:
rv=_request_ctx_stack.pop() # LocalStack.pop
def pop(self):# self是LocalStack对象
stack=getattr(self._local,"stack",None)——>[]对应的是一个列表
"_request_ctx_stack=LocalStack={
_local:{
__storage__:{9527:{stack:[CTX<request,session>]}}
__ident_func__:get_ident 一旦执行就会是int的线程数字
}
}"
else:最终执行这个方法
return stack.pop() 从列表中删除CTX<request,session>,变成空列表
# 总结
"_request_ctx_stack=LocalStack={
_local:{
__storage__:{9527:{stack:[CTX<request,session>]}}
__ident_func__:get_ident 一旦执行就会是int的线程数字
}
}"
1、LocalStack.push 新增CTX对象到 __storage__:{9527:{stack:[CTX<request,session>]}}
2、LocalStack.top 获取到push新增的Flask.request对象
3、LocalStack.pop 删除线程对应的CTX<request,session> 1、上下文管理笔记
如果类中有.get时候会有三种情况
属性,方法,__getattr__
如果出现同样的名字的时候:方法>属性>__getattr
2、self判定
1、如果函数中当作参数传进去的时候,里面的函数第一个self是函数的对象,传进来的self当作第二参数
2、getattr方法会用到特别多
__getattr__(对象,'属性值或方法')
|
|