郑统京 发表于 2023-3-27 01:35:36

深度刨析Flask请求上下文

深度刨析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_identfrom 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__ 通过空字典中括号取值,没有这个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=value # 这个通过索引取值的时候就会报错KeyError执行到下面
                                                            except KeyError:
                                                                storage={name:value}# { 9527:{stack:[]} }
                                                rv.append(obj) 就是在
                                                return rv
                            10、此时的经过ctx.push后
                              global.py中的公共变量随之发生变化了:
                              从之前的__storage__:{} ——>{9527:{stack:}}
                              _request_ctx_stack=LocalStack={_local:{
                                                                            __storage__:{9527:{stack:}}
                                                                            __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:}}
                                                      __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__ 这里面的运行结果是
                            这个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:}}
                                                      __ident_func__:get_ident 一旦执行就会是int的线程数字
                                                          }
                                             }"
                              else:最终执行这个方法
                                    return stack.pop() 从列表中删除CTX<request,session>,变成空列表
# 总结
"_request_ctx_stack=LocalStack={
                              _local:{
                                        __storage__:{9527:{stack:}}
                                        __ident_func__:get_ident 一旦执行就会是int的线程数字
                                          }
                              }"
1、LocalStack.push 新增CTX对象到 __storage__:{9527:{stack:}}
2、LocalStack.top 获取到push新增的Flask.request对象
3、LocalStack.pop删除线程对应的CTX<request,session> 1、上下文管理笔记
如果类中有.get时候会有三种情况
    属性,方法,__getattr__
    如果出现同样的名字的时候:方法>属性>__getattr
2、self判定
    1、如果函数中当作参数传进去的时候,里面的函数第一个self是函数的对象,传进来的self当作第二参数
    2、getattr方法会用到特别多
      __getattr__(对象,'属性值或方法')

页: [1]
查看完整版本: 深度刨析Flask请求上下文