成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

flask中current_app、g、request、session源碼的深究和理解

meteor199 / 3130人閱讀

摘要:本文是我在學(xué)習(xí)中對上下文和幾個類似全局變量的思考和研究,也有我自己的理解在內(nèi)。為了研究中的,我找到定義在的源碼可以看到主要由等組成,我先來分析和其實和原理上是一樣的,所以將其歸為一類,稱為請求上下文。

本文是我在學(xué)習(xí)flask中對上下文和幾個類似全局變量的思考和研究,也有我自己的理解在內(nèi)。

為了研究flask中的current_app、g、request、session,我找到定義在global.py的源碼:

# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))

可以看到主要由_lookup_req_object、_lookup_app_object、_find_app等組成,我先來分析request和session
其實request和session原理上是一樣的,所以將其歸為一類,稱為請求上下文。

我們從最里面看起,partial(_lookup_req_object, "request"),最外層是一個偏函數(shù),不過這不是重點,它主要是將"request"傳給_lookup_req_object,沒有其他含義, 順著_lookup_req_object找到它的源碼

def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
    raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)

從最后的return可以看到,這個函數(shù)的主要功能是從top中取出鍵值為"request"的內(nèi)容,top是一個字典,top從_request_ctx_stack.top中來,在上面的源碼中 _request_ctx_stack = LocalStack(),從名字來看LocalStack應(yīng)該是一個棧類,應(yīng)該有pop,push,top方法,我繼續(xù)找到源碼:

def __init__(self):
    self._local = Local()
...
...
def push(self, obj):
    """Pushes a new item to the stack"""
    rv = getattr(self._local, "stack", None)
    if rv is None:
        self._local.stack = rv = []
    rv.append(obj)
    return rv

def pop(self):
    """Removes the topmost item from the stack, will return the
    old value or `None` if the stack was already empty.
    """
    stack = getattr(self._local, "stack", None)
    if stack is None:
        return None
    elif len(stack) == 1:
        release_local(self._local)
        return stack[-1]
    else:
        return stack.pop()

@property
def top(self):
    """The topmost item on the stack.  If the stack is empty,
    `None` is returned.
    """
    try:
        return self._local.stack[-1]
    except (AttributeError, IndexError):
        return None

可以看到LocalStack()這個類有一個屬性self._local = Local(),對應(yīng)另一個類,繼續(xù)看源碼:

def __init__(self):
    object.__setattr__(self, "__storage__", {})
    object.__setattr__(self, "__ident_func__", get_ident)
...
...
def __getattr__(self, name):
    try:
        return self.__storage__[self.__ident_func__()][name]
    except KeyError:
        raise AttributeError(name)

def __setattr__(self, name, value):
    ident = self.__ident_func__()
    storage = self.__storage__
    try:
        storage[ident][name] = value
    except KeyError:
        storage[ident] = {name: value}
         

我截取了幾個重要的函數(shù),LocalStack()中的push,用到了Local()中的__setattr__();pop用到了__getattr__(),看到push和pop都是對"stack"這個鍵值進行查詢和賦值,我們轉(zhuǎn)到Local()這個類中,這個類有兩個實例屬性,__storage__和__ident_func__,前者是一個字典,后者是一個函數(shù),我們看一下這個get_ident函數(shù),查看源碼:

def get_ident(): # real signature unknown; restored from __doc__
    """
    get_ident() -> integer

    Return a non-zero integer that uniquely identifies the current thread
    amongst other threads that exist simultaneously.
    This may be used to identify per-thread resources.
    Even though on some platforms threads identities may appear to be
    allocated consecutive numbers starting at 1, this behavior should not
    be relied upon, and the number should be seen purely as a magic cookie.
    A thread"s identity may be reused for another thread after it exits.
    """
    return 0

顯然這個函數(shù)不是python寫的,因為它來自_thread.py,是一個底層庫,從名字可以猜到和線程有關(guān),根據(jù)描述,它返回一個非零整數(shù),代表了當前線程id,我們再看看__setattr__這個方法,它其實是一個字典嵌套列表再嵌套字典的數(shù)據(jù),__storage__是一個字典,它里面的鍵值被賦值為當前線程id,這個鍵值對應(yīng)的值是另一個字典:{"stack":["request":r_val,"session":s_val]},這樣和前面聯(lián)系起來就很好理解了,Local()中的__storage__存儲的格式為{thread_id:{"stack":["request":r_val,"session":s_val]}},LocalStack()中的top方法,返回了"stack"中最后一個加入的元素,也就是最新的元素,我自己理解為服務(wù)器接受的最新的請求,在框架外看起來request和session是一個全局變量,其實內(nèi)部已經(jīng)由進程id將其分隔開了,即使同時有多個請求過來,進程間的數(shù)據(jù)也不會混亂。

同理current_app和g也一樣,唯一不同的是,current_app、g和request、session是兩個不同的實例,注意前面 _request_ctx_stack = LocalStack()、_app_ctx_stack = LocalStack(),所以"stack"中存的數(shù)據(jù)也不一樣,current_app和g稱為應(yīng)用上下文,兩者還是有區(qū)別的。
LocalProxy 則是一個典型的代理模式實現(xiàn),它在構(gòu)造時接受一個 callable 的參數(shù)(比如一個函數(shù)),這個參數(shù)被調(diào)用后的返回值本身應(yīng)該是一個 Thread Local 對象。對一個 LocalProxy 對象的所有操作,包括屬性訪問、方法調(diào)用(當然方法調(diào)用就是屬性訪問)甚至是二元操作,都會轉(zhuǎn)發(fā)到那個 callable 參數(shù)返回的 Thread Local 對象上。
LocalProxy 的一個使用場景是 LocalStack 的 call 方法。比如 my_local_stack 是一個 LocalStack 實例,那么 my_local_stack() 能返回一個 LocalProxy 對象,這個對象始終指向 my_local_stack 的棧頂元素。如果棧頂元素不存在,訪問這個 LocalProxy 的時候會拋出 RuntimeError。
需要注意的是,如果需要離線編程,尤其在寫測試代碼時,需要將應(yīng)用上下文push到棧中去,不然current_app會指向空的_app_ctx_stack棧頂,自然也就無法工作了。
我們可以通過current_app的值來判斷是否進入應(yīng)用上下文中,可以用app.app_context().push()來進入應(yīng)用上下文。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/44734.html

相關(guān)文章

  • 深入 Flask 源碼理解 Context

    摘要:主要的作用是將維護的字典中鍵為對應(yīng)的值定義為。如果沒有,則會將當前到中,同時將加入列表中否則添加。注意清理之后的動作。上述代碼涉及到,它強調(diào)必須是一個可調(diào)用對象。后期的工作之一是了解。這僅僅是我的個人理解。實際上這是解決多個實例運行的問題。 Flask 中的上下文對象 知乎問題 編程中什么是「Context(上下文)」 已經(jīng)能夠簡單地說明什么是 Context,它是一個程序需要的外部對...

    ninefive 評論0 收藏0
  • flask 上下文實現(xiàn)

    摘要:值得注意的是這個對象在創(chuàng)建時,將實例的本身作為實參傳入自身,因此,。到這里想必已經(jīng)很清楚了就是指對象就是對應(yīng)每次請求創(chuàng)建的對象通過將與關(guān)聯(lián)起來總結(jié)創(chuàng)建了,這個對應(yīng)的上下文,就是每響應(yīng)一個請求,就會創(chuàng)建一個對象,這個對象對應(yīng)的上下文,就是 引言 本文主要梳理了flask的current_app, request, session, g的實現(xiàn)原理 源碼說明 本文使用flask 0.5 版本...

    lncwwn 評論0 收藏0
  • 關(guān)于Flask-SQLAlchemy事務(wù)提交有趣探討

    摘要:最近在開發(fā)的時候遇到這樣一個問題我就好奇了這樣還報不在中的錯沒有顯示調(diào)用啊加一行測試無奈,一個一個翻到之間調(diào)用的每一個函數(shù),終于在找到可疑點但是這里也沒有顯式提交。為什么接下來總結(jié)下大神們的探討。 最近在開發(fā)mdwiki的時候遇到這樣一個問題.Post is unbond to session.我就好奇了 post=Post.query.filter_by(location=locat...

    BlackHole1 評論0 收藏0
  • flask 核心 之 應(yīng)用上下文 及 請求上下文

    摘要:的上下文對象有兩種上下文,分別是請求上下文請求的對象,封裝了請求的內(nèi)容,生命周期請求處理完就結(jié)束了根據(jù)請求中的,重新載入該訪問者相關(guān)的會話信息應(yīng)用上下文處理請求時用作臨時存儲的對象。 Werkzeugs 是 Flask 的底層WSGI庫。 什么是WSGI? showImg(https://s1.ax1x.com/2018/11/13/iOqdKS.jpg); 一段簡單的app: def...

    tinna 評論0 收藏0
  • flask 源碼解析:上下文

    摘要:但是這些對象和全局變量不同的是它們必須是動態(tài)的,因為在多線程或者多協(xié)程的情況下,每個線程或者協(xié)程獲取的都是自己獨特的對象,不會互相干擾。中有兩種上下文和。就是實現(xiàn)了類似的效果多線程或者多協(xié)程情況下全局變量的隔離效果。 這是 flask 源碼解析系列文章的其中一篇,本系列所有文章列表: flask 源碼解析:簡介 flask 源碼解析:應(yīng)用啟動流程 flask 源碼解析:路由 flas...

    Labradors 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<