亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

深入 Flask 源碼理解 Context

ninefive / 3147人閱讀

摘要:主要的作用是將維護(hù)的字典中鍵為對(duì)應(yīng)的值定義為。如果沒(méi)有,則會(huì)將當(dāng)前到中,同時(shí)將加入列表中否則添加。注意清理之后的動(dòng)作。上述代碼涉及到,它強(qiáng)調(diào)必須是一個(gè)可調(diào)用對(duì)象。后期的工作之一是了解。這僅僅是我的個(gè)人理解。實(shí)際上這是解決多個(gè)實(shí)例運(yùn)行的問(wèn)題。

Flask 中的上下文對(duì)象

知乎問(wèn)題 編程中什么是「Context(上下文)」 已經(jīng)能夠簡(jiǎn)單地說(shuō)明什么是 Context,它是一個(gè)程序需要的外部對(duì)象,類(lèi)似于一個(gè)全局變量。而這個(gè)變量的值會(huì)根據(jù)提供的值而改變。

Flask 中有分為請(qǐng)求上下文和應(yīng)用上下文:

對(duì)象 Context類(lèi)型 說(shuō)明
current_app AppContext 當(dāng)前的應(yīng)用對(duì)象
g AppContext 處理請(qǐng)求時(shí)用作臨時(shí)存儲(chǔ)的對(duì)象
request RequestContext 請(qǐng)求對(duì)象,封裝了Http請(qǐng)求的內(nèi)容
session RequestContext 用于存儲(chǔ)請(qǐng)求之間需要記住的值

Flask 分發(fā)請(qǐng)求之前激活程序請(qǐng)求上下文,請(qǐng)求處理完成后再將其刪除。

Flask 中的 Context 是通過(guò)棧來(lái)實(shí)現(xiàn)。


Flask 的 Context 實(shí)現(xiàn)

Flask 的核心功能依賴于 Werkzeug 庫(kù)。

_app_ctx_stack & _request_ctx_stack

這兩種棧定義在 flask/global.py 中。

_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()

首先需要了解一下 Werkzeug 中關(guān)于 LcoalStack 的相關(guān)內(nèi)容。

Local 類(lèi)

Local 是定義了一個(gè) __storage__ 字典,其中的鍵為 threadid 值。

class Local(object):
    __slots__ = ("__storage__", "__ident_func__")
    
    def __init__(self):
        object.__setattr__(self, "__storage__", {})
        object.__setattr__(self, "__ident_func__", get_ident)
        
    def __setattr__(self, name, value):
        ident  = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value
        except KeyError:
            raise AttributeError(name)
    ...

LocalStack 類(lèi)

LocalStack 則內(nèi)部維護(hù)一個(gè) Local 實(shí)例。主要的作用是將 Local 維護(hù)的 __storage__ 字典中鍵為 __ident_func__() 對(duì)應(yīng)的值定義為 {"stack" : [] }。

class LocalStack(object):
    def __init__(self):
        self._local = Local()
        
    def push(self, obj):
        rv = getattr(self._local, "stack", None)
        if rv is None:
            self._local.stack = rv = []
        rv.append(obj)
        return rv
        
    def pop(self, obj):
        pass

LocalProxy 類(lèi)

LocalProxy類(lèi)是一個(gè)代理類(lèi),應(yīng)用到設(shè)計(jì)模式當(dāng)中的代理模式。簡(jiǎn)單地講,我們不需要去了解當(dāng)前的環(huán)境,而直接去操作這個(gè) Proxy 類(lèi),這個(gè) Proxy 類(lèi)會(huì)將所有的操作反饋給正確的對(duì)象。

class LocalProxy(object):
    __slots__ = ("__local", "__dict__", "__name__")
    def __init__(self, local, name=None):
        object.__setattr__(self, "_LocalProxy__local", local)
        object.__setattr__(self, "__name__", name)
    
    def _get_current_object(self):
        # 通過(guò)此方法獲取被代理的對(duì)象
        if not hasattr(self.__local, "__release_local__")
            return self.__local
        try:
            return gerattr(self.__local,self.__name__)
        except Attribute:
            raise RuntimeError("no object bound to %s" % self.__name__)
    ...
    # 其他操作
request & RequestContext

Flask 源碼中關(guān)于 request 的定義:

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

從源碼可以看出,request_request_ctx_stack 棧頂元素的一個(gè)屬性。實(shí)際上 _request_ctx_stack 棧中的元素是 ReuqestContext 對(duì)象的實(shí)例, 而 ReuqestContext 中包含了 request 請(qǐng)求的所有信息,包括 Session 信息。

class ReuqestContext(object):
    def __init__(self, app, environ, request=None):
        if reuqest is None:
            request  = Request(environ)
        self.requst = request
        self.app = app 
        self.session = None
        ...
        # 這個(gè)列表包含了與 request 相關(guān)聯(lián)的 Application
        self._implicit_app_ctx_stack = []
        self.match_request()

    def push(self, object):
        """
        這里需要實(shí)現(xiàn)的是:當(dāng) RequestContext push 到
        _request_ctx_stack 時(shí), 需要檢測(cè)是否有對(duì)應(yīng)的
        AppContext。如果沒(méi)有,則會(huì)將當(dāng)前 self.app push
        到 AppContext 中,同時(shí)將self.app 加入
        _implicit_app_ctx_stack 列表中; 否則
        _implicit_app_ctx_stack 添加 None。
        """
        pass
        
    def pop(self):
        """
        當(dāng) ReuqestContext 彈出 _request_ctx_stack 的
        方法。注意:request 清理之后的動(dòng)作。如執(zhí)行
        teardown_request。
        """
        pass

這里傳入的 app,就是 Flask 的程序?qū)嵗?
RequestContext 實(shí)例的創(chuàng)建在 Flask 類(lèi)方法中。

class Flask(_PackageBoundObject):
    ...
    request_class = ReuqestContext
    def wsgi_app(self, environ, start_response):
        ctx = self.request_class(environ)
        ctx.push
        ...
        
    def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)

Flask 中 Request 對(duì)象繼承了 Werkzeug 中的 Request 對(duì)象。
上述代碼涉及到 WSGI,它強(qiáng)調(diào) Appication 必須是一個(gè)可調(diào)用對(duì)象。
后期的工作之一是了解 WSGI

Session

在 session.py 文件中定義了 有關(guān)Session的內(nèi)容。Flask 中 Session 是構(gòu)建在 Cookie 上面的。其中定義了關(guān)于 Session 的接口。

class SessionMixin(object):
    """定義了Session的最小屬性"""
    
class SecureCookieSession(CallDict, SessionMixin):
    """ CallDict 是 werkzeug 中的數(shù)據(jù)結(jié)構(gòu) """

class NullSession(SecureCookieSession):
    """ 定義了空 session 結(jié)構(gòu) """
    
class SessionInterface(object):
    """ 定義了 Session接口的屬性,依賴于 app.config 
    中的信息。同時(shí),規(guī)定了只要是繼承SessionInterface
    必須實(shí)現(xiàn) open_session 和 save_session 方法
    """
class SecureCookieSessionInterface(SessionInterface):
    """ 
    主要是實(shí)現(xiàn)了 open_session 和 save_session 方法
    """

如下代碼則是 session 的應(yīng)用。

# flask/app.py
class Flask(_PackageBoundObject):
    session_interface = SecureCookieSessionInterface()
    def open_session(self, request):
        return self.session_interface.open_session(self, request)
        
    def save_session(self, session, response)
        return self.session_interface.save_session(
            self, session, response)
            
    def process_response(self, response):
        ctx = _request_ctx_stack.top
        ...
        if not self.session_interface.is_null_session(ctx.session):
            self.save_session(ctx.session, response)

#ReuqestContext
class ReuqestContext():
    def push(self, object):
        ...
        self.session = self.app.open_session(self.reuqest)
        if self.session is None:
            self.session = self.app.make_null_session()
        ...

sessionRequestContext 中屬性,所以代理說(shuō)明如下:

session = LocalProxy(partial(_lookup_req_object,"session")
current_app & g

一般來(lái)講, 在 Flask Web 開(kāi)發(fā)時(shí), Flask的實(shí)例是延遲創(chuàng)建的。也就是說(shuō) AppContext還沒(méi)有壓入 _app_ctx_stack 中,所以我們?cè)诰帉?xiě)代碼時(shí),是無(wú)法獲取完整的 Flask 實(shí)例的屬性。而當(dāng)用戶訪問(wèn)時(shí),程序的實(shí)例已經(jīng)初始化完成了,因此我們采用 current_app代理獲取當(dāng)前 app。這僅僅是我的個(gè)人理解。實(shí)際上這是解決 多個(gè) Flask 實(shí)例運(yùn)行的問(wèn)題。

current_app是獲取 _app_ctx_stack 棧頂 AppContext實(shí)例元素的代理.

def _find_app():
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
    return top.app
current_app = LocalProxy(_find_app)

flask.g 是存儲(chǔ)一下資源信息的,如數(shù)據(jù)庫(kù)連接信息。更多應(yīng)用的則是體現(xiàn)在 Flask 擴(kuò)展當(dāng)中。

def _lookup_app_object(name):
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
        return getattr(top,name)
g = LocalProxy(partical(_lookup_app_object, "g"))

# flask.app.py
class Flask(_PackageBoundObject):
    app_ctx_globals_class = _AppCtxGlobals #實(shí)現(xiàn)的是類(lèi)似字典的功能

# AppContext
class AppContext(object):
    def __init__(self, app):
        self.g = self.app.app_ctx_globals_class()

#RequestContext
class RequestContext(object):
    #定義與request相關(guān)的 g 變量
    def _get_g(self):
        return _app_ctx_stack.top.g
    def _set_g(self, value):
        _app_ctx_stack.top.g = value
    g = property(_get_g, _set_g)
    del _get_g, _set_g   

上述代碼存在一個(gè)疑問(wèn)是 g 對(duì)象是基于請(qǐng)求的,每次請(qǐng)求都會(huì)重置。那么 g 為什么不是 RequestContext 而是 AppContext ?
flask.g API 文檔 中說(shuō)明了 g 變量的改動(dòng)。


個(gè)人博客

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/37874.html

相關(guān)文章

  • 深入理解flask框架(2):應(yīng)用上下文與請(qǐng)求上下文

    摘要:實(shí)現(xiàn)一個(gè)進(jìn)程中擁有多個(gè)應(yīng)用上下文機(jī)制依賴的數(shù)據(jù)結(jié)構(gòu)上下文機(jī)制的實(shí)現(xiàn)基于的。 什么是上下文? flask框架中的上下文本質(zhì)上就是兩個(gè)類(lèi),我們可以先看一下他的初始化函數(shù):應(yīng)用上下文 class AppContext(object): The application context binds an application object implicitly to the c...

    wushuiyong 評(píng)論0 收藏0
  • 深入理解flask框架(4):session

    摘要:中的實(shí)現(xiàn)是基于。打開(kāi)源碼的文件,我們可以看到最后的接口類(lèi)中,主要有兩個(gè)函數(shù)。這個(gè)系列就此完結(jié)。 flask中session的實(shí)現(xiàn)是基于cookie。打開(kāi)flask源碼的session.py文件,我們可以看到最后的接口類(lèi)中,主要有open_session,save_session兩個(gè)函數(shù)。 class SecureCookieSessionInterface(SessionInterfa...

    PingCAP 評(píng)論0 收藏0
  • flask 源碼解析:應(yīng)用啟動(dòng)流程

    摘要:中有一個(gè)非常重要的概念每個(gè)應(yīng)用都是一個(gè)可調(diào)用的對(duì)象。它規(guī)定了的接口,會(huì)調(diào)用,并傳給它兩個(gè)參數(shù)包含了請(qǐng)求的所有信息,是處理完之后需要調(diào)用的函數(shù),參數(shù)是狀態(tài)碼響應(yīng)頭部還有錯(cuò)誤信息。一般來(lái)說(shuō),嵌套的最后一層是業(yè)務(wù)應(yīng)用,中間就是。 文章屬于作者原創(chuàng),原文發(fā)布在個(gè)人博客。 WSGI 所有的 python web 框架都要遵循 WSGI 協(xié)議,如果對(duì) WSGI 不清楚,可以查看我之前的介紹文章。 ...

    whatsns 評(píng)論0 收藏0
  • flask 源碼解析:上下文

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

    Labradors 評(píng)論0 收藏0
  • flask 源碼解析:簡(jiǎn)介

    摘要:簡(jiǎn)介官網(wǎng)上對(duì)它的定位是一個(gè)微開(kāi)發(fā)框架。另外一個(gè)必須理解的概念是,簡(jiǎn)單來(lái)說(shuō)就是一套和框架應(yīng)用之間的協(xié)議。功能比較豐富,支持解析自動(dòng)防止攻擊繼承變量過(guò)濾器流程邏輯支持代碼邏輯集成等等。那么,從下一篇文章,我們就正式開(kāi)始源碼之旅了 文章屬于作者原創(chuàng),原文發(fā)布在個(gè)人博客。 flask 簡(jiǎn)介 Flask 官網(wǎng)上對(duì)它的定位是一個(gè)微 python web 開(kāi)發(fā)框架。 Flask is a micro...

    megatron 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<