设为首页 收藏本站
查看: 1520|回复: 0

[经验分享] 深度刨析Flask请求上下文

[复制链接]
累计签到:503 天
连续签到:2 天
发表于 2023-3-27 01:35:36 | 显示全部楼层 |阅读模式
深度刨析flask底层调用机制
# 请求上文
1from flask import Flask
    app=Flask(__name__)
    app.run() 是入口
        
def run(self) selfapp
            ...
            from werkzeug.serving import run_simple
            2run_simple(host,post,self) selfapp并且调用app__call__方法
               
def __call__(self,environ,start_response) selfapp
                    return self.wsgi_app(environ,start_response)
                    3self.wsgi_app(environ,start_response)
                        def wsgi_app(self,environ,start_response) selfapp对象
                           
ctx = self.request_context(environ)
                                def request_context(self,environ) selfapp对象
                                    
return ReqeustContext(self,environ)
                                    4ReqeustContext(self,environ) 类实例化会调用RC对象__init__self(app)当作参数传入到里面
                                       
class RequestContext:
                                            def __init__(self,app,environ,request=None,session=None):selfRC对象,app是传进的self
                                                self.app=app
                                                request=app.request_class(environ) # 将原始请求变成flask.request
                                                self.request=reqeust # RC对象添加request属性
                                                
self.session=session # 当前sessionNone
                            5ctx=RC对象<request(flask形式的属性),session>
                            6ctx.push #ctxRC对象
                                
def push(self) # selfctx对象
                                    
top=_request_ctx_stack.top
                                        global.py中可以看到 _request_ctx_stack=LocalStack() 会调用LocalStack__init__方法
                                       
class LocalStack:
                                            def __init__(self): # selfLocalStack
                                                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的线程数字
                                                
}
                                    8top=_request_ctx_stack.top = _request_ctx_stack=LocalStack={  _local:{
                                                                                                        __storage__:{}
                                                                                                        __ident_func__:get_ident 一旦执行就会是int的线程数字
                                                                                                            
}
                                                                                                  }.top
                                        LocalStack.top 推断三种可能,property方法,属性,__getattr__方法,优先级一次从左到右
                                       
@property
                                        def top(self) selfLocalStack对象
                                       
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) selfctx=RC对象,当作参数传进去
                                       
def push(self,obj) # 此时self_request_ctx_stack对象,obj是传进来的self也就是ctx<requestsession>
                                            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) selfLocal对象
                                                            
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的线程数字
                                                                          
}
                                                               }
# 请求下文
1request=LocalProxy(partial(_lookup_req_object,"request"))
       def _lookup_req_object("name"): # name=”request“
            top=_request_ctx_stack.top # 执行topproperty方法
               
_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
       2request=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):selfLocalProxy对象,localNewPartial的函数地址没有执行
                        
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
3request=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) #selfLocalProxy对象,_get_current_object()方法
                    
4def get_current_object(self):# selfLocalProxy对象
                        
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去对应的属性或方法
4ctx.auto_pop(error) CTX<request,session>对象
   
def auto_pop(self,error) #selfCTX对象
        
...
        else:
            self.pop(exc) #selfCTX对象
               
def pop(self,exc=_sentinel):
                    ...
                    finally:
                        rv=_request_ctx_stack.pop() # LocalStack.pop
                            def pop(self):# selfLocalStack对象
                                
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的线程数字
                                          
}
                                }"
1LocalStack.push 新增CTX对象到 __storage__:{9527:{stack:[CTX<request,session>]}}
2LocalStack.top 获取到push新增的Flask.request对象
3LocalStack.pop  删除线程对应的CTX<request,session>
1、上下文管理笔记
如果类中有.get时候会有三种情况
    属性,方法,__getattr__
    如果出现同样的名字的时候:方法>属性>__getattr
2self判定
    1、如果函数中当作参数传进去的时候,里面的函数第一个self是函数的对象,传进来的self当作第二参数
    2getattr方法会用到特别多
        __getattr__(对象,'属性值或方法')



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-1003685-1-1.html 上篇帖子: drf实现登录和注册功能 下篇帖子: 浅谈WeSocket实时通讯过程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表