Flask开发高级:上【下】文管理源码解析

回顾

前一篇中,我们已经知道Flask是通过把用户的请求信息放入到线程栈中进行存储。例如你的线程id是9528,你进来后,生成一个stack,stack存放的就是9528的请求信息。你是9529、9531等依次对应,所有用户的请求信息都是这样存储。

# {9528:{stack :[ctx(request,session)]}} # 存放的是线程id为9528的请求信息

开始

接着前一篇继续,在push中,我们知道了Flask的上下文存储机制:

 def push(self, obj): # obj= ctx = request_context=(request,session)
 
    """Pushes a new item to the stack"""
# 这个self往上找,self._local = Local=[{},get_ident]
    rv = getattr(self._local, "stack", None)
    if rv is None:
        self._local.stack = rv = [] # {9528:{stack :[]}}
# _local对象.stack执行__setattr__方法
    rv.append(obj)
# {9528:{stack :[ctx(request,session)]}}
    return rv

往回翻到LocalStack这里:

# context locals
_request_ctx_stack = LocalStack() # {9528:{stack :[ctx(request,session)]}}
# _request_ctx_stack 请求上下文栈,实例化LocalStack(),执行__init__方法
# _request_ctx_stack._local = Local=[{},get_ident]
#最后变为: [ {9528:{stack :[ctx(request,session)]}},get_ident]

知道了LocalStack存储的值是[ {9528:{stack :[ctx(request,session)]}},get_ident]这种形式的。再往下看:

_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request")) #partial 偏函数
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))

点击进入到_lookup_req_object中:

def _lookup_req_object(name): # name = request
    top = _request_ctx_stack.top
# _request_ctx_stack._local = [ {9528:{stack :[ctx(request,session)]}},get_ident]
# 在实例内部别忘了("__storage__", "__ident_func__")与上面数组的小标是对应的
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    return getattr(top, name)

进入到top中:

def top(self): # self._local = [ {9528:{stack :[ctx(request,session)]}},get_ident]
    """The topmost item on the stack.  If the stack is empty,
    `None` is returned.
    """
    try:
        return self._local.stack[-1]
# 对象.stack[-1],调用_local对象中的__getattr__方法
    except (AttributeError, IndexError):
        return None

进入到_local对象中,找到__getattr__方法:

 def __getattr__(self, name): # name = stack 
    try:
# _request_ctx_stack._local = [ {9528:{stack :[ctx(request,session)]}},get_ident]
# 在实例内部别忘了("__storage__", "__ident_func__")与上面数组的小标是对应的
        return self.__storage__[self.__ident_func__()][name]
# self.__ident_func__()获取线程id9528,name就是stack 
# 拿到[ctx(request,session)] ,然后返回
    except KeyError:
        raise AttributeError(name)

回到top这里:

def top(self): # self._local = [ {9528:{stack :[ctx(request,session)]}},get_ident]
    """The topmost item on the stack.  If the stack is empty,
    `None` is returned.
    """
    try:
        return self._local.stack[-1] # 返回 ctx (request,session)
# 对象.stack[-1],调用_local对象中的__getattr__方法
    except (AttributeError, IndexError):
        return None

再回到_lookup_req_object这里:

def _lookup_req_object(name): # name = request
    top = _request_ctx_stack.top # 拿到 ctx (request,session)
# _request_ctx_stack._local = [ {9528:{stack :[ctx(request,session)]}},get_ident]
# 在实例内部别忘了("__storage__", "__ident_func__")与上面数组的小标是对应的
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    return getattr(top, name) # # name = request

回到partial 这里:

_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request")) #partial 偏函数
# 取出request对象
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))

进入到LocalProxy中:

def __init__(self, local, name=None): # local = partial >可得> request
    object.__setattr__(self, "_LocalProxy__local", local) # partial >>> request
# __setattr__为LocalProxy这个类添加一个__local属性
    object.__setattr__(self, "__name__", name)
# local是partial偏函数,可以被执行,local中没有__release_local__这个属性
    if callable(local) and not hasattr(local, "__release_local__"): # True
        # "local" is a callable that is not an instance of Local or
        # LocalManager: mark it as a wrapped function.
        object.__setattr__(self, "__wrapped__", local) # partial >>> request

完了,到这里就结束了?别着急,还记得在Flask中可以用request.method去判断前端传送数据所用的方法吧。.method实质是调用了request对象的__getattr__方法,由前面可知,request对象其实就是LocalProxy对象,那我们进LocalProxy对象去找找__getattr__方法:

def __getattr__(self, name): # 例如 .method  则name = method
    if name == "__members__":
        return dir(self._get_current_object())
    return getattr(self._get_current_object(), name) # name = method

进入到_get_current_object中:

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__"): # True
        return self.__local() # 往上翻发现,返回的就是request对象
    try:
        return getattr(self.__local, self.__name__)
    except AttributeError:
        raise RuntimeError("no object bound to %s" % self.__name__)

回到__getattr__这里,一切都明白了:

def __getattr__(self, name): # 例如 .method  则name = method
    if name == "__members__":
        return dir(self._get_current_object())
    return getattr(self._get_current_object(), name) # name = method
# self._get_current_object() 返回一个request对象

请求中的所有数据都是通过反射的方式,从request中获取的

总结

Flask上下文管理全流程解析:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值