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上下文管理全流程解析:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章