上下文管理流程图、以及自己总结的源码代码

老师画的

自己整理的

 

同学整理的

 

 

 以request.method为例,进行源码查找

from flask import Flask,request,session,g,current_app
------>

request = LocalProxy(partial(_lookup_req_object, 'request')) #类后面加括号,表示是对象
------>

    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)

还在这个文件下,找下面的getattr方法
    def __getattr__(self, name):     ##name=“method”
        if name == '__members__':
            return dir(self._get_current_object())

##把下面的拆分成两部分,obj=self._get_current_object() ##对左边这句话的注释:去ctx中获取request
##return getattr(obj,name)   把下面这一行拆成两部分;## 这个name就是上数4行的 》》》 name=“method”这个method,是字符串,这行可改成return getattr(obj,“method”) ,也就是request.method
        return getattr(self._get_current_object(), name)

因为我们写的py文件中是要获取request.method,因此先要获取request,再获取method,也就是上面的去ctx中获取request,再去request中获取method,

》》》点击   return getattr(self._get_current_object(), name)
------>

    def _get_current_object(self):
        """Return the current object.  This is useful if you want the real
        object behind the proxy at a time for performance reasons or because
        you want to pass the object into a different context.
        """
        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__)
》》同一个文件中,看看__local()是个什么鬼,请看下面代码》》

    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 _get_current_object(self):
        """Return the current object.  This is useful if you want the real
        object behind the proxy at a time for performance reasons or because
        you want to pass the object into a different context.
        """
        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__)
》》》看到上面之后,直接在pycharm上点击左边的一个globals.py文件,这个是我们刚看过的源码文件,找到下面这行
------>

request = LocalProxy(partial(_lookup_req_object, 'request'))  ##这个就是我们上面说的函数
------>点击上面的红色字体,进入下面

def _lookup_req_object(name):##name=request
    ##top=ctx(request,session)
    top = _request_ctx_stack.top ##_request_ctx_stack = LocalStack()就是这个对象,点击源码就能看到
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    ##获取ctx中的request对象》》(top)
    return getattr(top, name)
》》》》》》》》

再次回到这里__getattr__
    def __getattr__(self, name):     ##name=“method”
        if name == '__members__':
            return dir(self._get_current_object())
##obj=self._get_current_object() ##去ctx中获取request 》》》》request (老师举例的就是到守夜这了)    >>>>>>然后去method里面request.method就行
##return getattr(obj,name)   等价于return getattr(obj,“method”) ,也就是request.method
        return getattr(self._get_current_object(), name)
》》》》》

最后回到我们写的py文件,到下面这里
 request.method  ##这一句相当于执行守夜.method,(本质上是这样,路程有点曲折)

》》在request.method代码下面,我们还可用下面的args方法
   request.args   # LocalProxy.__getattr__(key='args')   # ctx中request, 再去request中获取args   ,这行,其实跟上面request.method操作是一样的,点击源码进去,跟request.method都是一样的,流程也是一样的,只是换了名字,换成了args,

——————————————————————————————————————————————
下面开始看session,还是在request.method下面加一行
  session['k1'] = 123  开始查看session的源码,点击我们写的代码,最上面导入的session,点进去如下
------>

session = LocalProxy(partial(_lookup_req_object, 'session')),##会到这里,发现跟上面的request是一样的,就是把request换成了session而已,也就是函数执行的默认参数不同了
------>LocalProxy再次进去看源码

    def __setitem__(self, key, value):
        ##obj = self.__get__current_object() ps:还继续拆分
        ##obj['k1]=123
        self._get_current_object()[key] = value
》》》》回到源码的globals.py文件中,点击 
session = LocalProxy(partial(_lookup_req_object, 'session'))
------>

进入之后,其实就是把这些都换成了session,上面的操作是request
def _lookup_req_object(name):##name=session
    ##top=ctx(request,session)
    top = _request_ctx_stack.top ##_request_ctx_stack = LocalStack()就是这个对象,点击源码就能看到
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    ##获取ctx中的session对象
    return getattr(top, name)
》》》

然后再到下面看源码,还是回到刚才去过的__setitem__中
session = LocalProxy(partial(_lookup_req_object, 'session'))##这就获取到了session对象
------>

    def __setitem__(self, key, value):
        ##obj = self.__get__current_object() 》》新加功能:    去ctx中获取session对象,(ps:session就是一个特殊的字典,因为里面有继承字典,再看下行代码注释)
        ##obj['k1]=123》》》新功能:在字典中赋值  
        self._get_current_object()[key] = value
》》》》》

上面说的赋值操作,就是我们写的代码, session['k1'] = 123 ,这就是赋值操作》》》》
   session['k1'] = 123  ## LocalProxy.__setitem__(key=k1,value=123) # ctx中session, 再去session中改k1设置值
   session['k1'] # #LocalProxy.__getitem__(key='k1') # ctx中session, 再去session中获取k1对应的值
这就是session里面的流程。。。

ps:问题,request和session是用的同一个ctx,也就是老师讲课举例所说的麻袋
View Code

自己写的全部py文件代码如下

from flask import Flask,request,session,g,current_app

app = Flask(__name__)


@app.route('/')
def hello_world():
    print(request) # LocalProxy.__str__
    request.method # LocalProxy.__getattr__(key='method') # ctx中request, 再去request中获取method
    request.args   # LocalProxy.__getattr__(key='args')   # ctx中request, 再去request中获取args


    session['k1'] = 123  # LocalProxy.__setitem__(key=k1,value=123) # ctx中session, 再去session中改k1设置值
    session['k1'] # LocalProxy.__getitem__(key='k1') # ctx中session, 再去session中获取k1对应的值

    return 'wupeiqi'

if __name__ == '__main__':
    app.__call__
    app.wsgi_app
    app.run()

"""
用户请求一旦到来:
    1. app.__call__

"""
View Code

 

这三个阶段,是我们自己定义的。

 

posted @ 2018-05-02 00:45  Justin壮志凌云  阅读(133)  评论(0)    收藏  举报