摘要:主要的作用是將維護的字典中鍵為對應的值定義為。如果沒有,則會將當前到中,同時將加入列表中否則添加。注意清理之后的動作。上述代碼涉及到,它強調必須是一個可調用對象。后期的工作之一是了解。這僅僅是我的個人理解。實際上這是解決多個實例運行的問題。
Flask 中的上下文對象
知乎問題 編程中什么是「Context(上下文)」 已經能夠簡單地說明什么是 Context,它是一個程序需要的外部對象,類似于一個全局變量。而這個變量的值會根據提供的值而改變。
Flask 中有分為請求上下文和應用上下文:
對象 | Context類型 | 說明 |
---|---|---|
current_app | AppContext | 當前的應用對象 |
g | AppContext | 處理請求時用作臨時存儲的對象 |
request | RequestContext | 請求對象,封裝了Http請求的內容 |
session | RequestContext | 用于存儲請求之間需要記住的值 |
Flask 分發請求之前激活程序請求上下文,請求處理完成后再將其刪除。
Flask 中的 Context 是通過棧來實現。
Flask 的核心功能依賴于 Werkzeug 庫。
_app_ctx_stack & _request_ctx_stack這兩種棧定義在 flask/global.py 中。
_request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack()
首先需要了解一下 Werkzeug 中關于 LcoalStack 的相關內容。
Local 類
Local 是定義了一個 __storage__ 字典,其中的鍵為 thread 的 id 值。
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 類
LocalStack 則內部維護一個 Local 實例。主要的作用是將 Local 維護的 __storage__ 字典中鍵為 __ident_func__() 對應的值定義為 {"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 類
LocalProxy類是一個代理類,應用到設計模式當中的代理模式。簡單地講,我們不需要去了解當前的環境,而直接去操作這個 Proxy 類,這個 Proxy 類會將所有的操作反饋給正確的對象。
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): # 通過此方法獲取被代理的對象 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 源碼中關于 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 棧頂元素的一個屬性。實際上 _request_ctx_stack 棧中的元素是 ReuqestContext 對象的實例, 而 ReuqestContext 中包含了 request 請求的所有信息,包括 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 ... # 這個列表包含了與 request 相關聯的 Application self._implicit_app_ctx_stack = [] self.match_request() def push(self, object): """ 這里需要實現的是:當 RequestContext push 到 _request_ctx_stack 時, 需要檢測是否有對應的 AppContext。如果沒有,則會將當前 self.app push 到 AppContext 中,同時將self.app 加入 _implicit_app_ctx_stack 列表中; 否則 _implicit_app_ctx_stack 添加 None。 """ pass def pop(self): """ 當 ReuqestContext 彈出 _request_ctx_stack 的 方法。注意:request 清理之后的動作。如執行 teardown_request。 """ pass
這里傳入的 app,就是 Flask 的程序實例。
RequestContext 實例的創建在 Flask 類方法中。
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 對象繼承了 Werkzeug 中的 Request 對象。
上述代碼涉及到 WSGI,它強調 Appication 必須是一個可調用對象。
后期的工作之一是了解 WSGI。
在 session.py 文件中定義了 有關Session的內容。Flask 中 Session 是構建在 Cookie 上面的。其中定義了關于 Session 的接口。
class SessionMixin(object): """定義了Session的最小屬性""" class SecureCookieSession(CallDict, SessionMixin): """ CallDict 是 werkzeug 中的數據結構 """ class NullSession(SecureCookieSession): """ 定義了空 session 結構 """ class SessionInterface(object): """ 定義了 Session接口的屬性,依賴于 app.config 中的信息。同時,規定了只要是繼承SessionInterface 必須實現 open_session 和 save_session 方法 """ class SecureCookieSessionInterface(SessionInterface): """ 主要是實現了 open_session 和 save_session 方法 """
如下代碼則是 session 的應用。
# 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() ...
session 是 RequestContext 中屬性,所以代理說明如下:
session = LocalProxy(partial(_lookup_req_object,"session")current_app & g
一般來講, 在 Flask Web 開發時, Flask的實例是延遲創建的。也就是說 AppContext還沒有壓入 _app_ctx_stack 中,所以我們在編寫代碼時,是無法獲取完整的 Flask 實例的屬性。而當用戶訪問時,程序的實例已經初始化完成了,因此我們采用 current_app代理獲取當前 app。這僅僅是我的個人理解。實際上這是解決 多個 Flask 實例運行的問題。
current_app是獲取 _app_ctx_stack 棧頂 AppContext實例元素的代理.
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 是存儲一下資源信息的,如數據庫連接信息。更多應用的則是體現在 Flask 擴展當中。
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 #實現的是類似字典的功能 # AppContext class AppContext(object): def __init__(self, app): self.g = self.app.app_ctx_globals_class() #RequestContext class RequestContext(object): #定義與request相關的 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 對象是基于請求的,每次請求都會重置。那么 g 為什么不是 RequestContext 而是 AppContext ?
flask.g API 文檔 中說明了 g 變量的改動。
個人博客
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/37874.html
摘要:實現一個進程中擁有多個應用上下文機制依賴的數據結構上下文機制的實現基于的。 什么是上下文? flask框架中的上下文本質上就是兩個類,我們可以先看一下他的初始化函數:應用上下文 class AppContext(object): The application context binds an application object implicitly to the c...
摘要:中的實現是基于。打開源碼的文件,我們可以看到最后的接口類中,主要有兩個函數。這個系列就此完結。 flask中session的實現是基于cookie。打開flask源碼的session.py文件,我們可以看到最后的接口類中,主要有open_session,save_session兩個函數。 class SecureCookieSessionInterface(SessionInterfa...
摘要:中有一個非常重要的概念每個應用都是一個可調用的對象。它規定了的接口,會調用,并傳給它兩個參數包含了請求的所有信息,是處理完之后需要調用的函數,參數是狀態碼響應頭部還有錯誤信息。一般來說,嵌套的最后一層是業務應用,中間就是。 文章屬于作者原創,原文發布在個人博客。 WSGI 所有的 python web 框架都要遵循 WSGI 協議,如果對 WSGI 不清楚,可以查看我之前的介紹文章。 ...
摘要:但是這些對象和全局變量不同的是它們必須是動態的,因為在多線程或者多協程的情況下,每個線程或者協程獲取的都是自己獨特的對象,不會互相干擾。中有兩種上下文和。就是實現了類似的效果多線程或者多協程情況下全局變量的隔離效果。 這是 flask 源碼解析系列文章的其中一篇,本系列所有文章列表: flask 源碼解析:簡介 flask 源碼解析:應用啟動流程 flask 源碼解析:路由 flas...
摘要:簡介官網上對它的定位是一個微開發框架。另外一個必須理解的概念是,簡單來說就是一套和框架應用之間的協議。功能比較豐富,支持解析自動防止攻擊繼承變量過濾器流程邏輯支持代碼邏輯集成等等。那么,從下一篇文章,我們就正式開始源碼之旅了 文章屬于作者原創,原文發布在個人博客。 flask 簡介 Flask 官網上對它的定位是一個微 python web 開發框架。 Flask is a micro...
閱讀 3020·2021-11-12 10:36
閱讀 4726·2021-09-22 10:57
閱讀 1558·2021-09-22 10:53
閱讀 2636·2019-08-30 15:55
閱讀 3493·2019-08-29 17:00
閱讀 3352·2019-08-29 16:36
閱讀 2463·2019-08-29 13:46
閱讀 1348·2019-08-26 11:45