成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Flask中的請求上下文和應(yīng)用上下文

開發(fā) 后端
在Flask中處理請求時(shí),應(yīng)用會(huì)生成一個(gè)“請求上下文”對象。整個(gè)請求的處理過程,都會(huì)在這個(gè)上下文對象中進(jìn)行。

[[190923]]

在Flask中處理請求時(shí),應(yīng)用會(huì)生成一個(gè)“請求上下文”對象。整個(gè)請求的處理過程,都會(huì)在這個(gè)上下文對象中進(jìn)行。這保證了請求的處理過程不被干擾。處理請求的具體代碼如下:

  1. def wsgi_app(self, environ, start_response): 
  2.  
  3.     with self.request_context(environ): 
  4.  
  5.         # with語句中生成一個(gè)`response`對象 
  6.  
  7.         ... 
  8.  
  9.     return response(environ, start_response)  

在Flask 0.9版本之前,應(yīng)用只有“請求上下文”對象,它包含了和請求處理相關(guān)的信息。同時(shí)Flask還根據(jù)werkzeug.local模塊中實(shí)現(xiàn)的一種數(shù)據(jù)結(jié)構(gòu)LocalStack用來存儲(chǔ)“請求上下文”對象。這在《一個(gè)Flask應(yīng)用運(yùn)行過程剖析 》中有所介紹。在0.9版本中,F(xiàn)lask又引入了“應(yīng)用上下文”的概念。本文主要Flask中的這兩個(gè)“上下文”對象。

LocalStack

在介紹“請求上下文”和“應(yīng)用上下文”之前,我們對LocalStack簡要做一個(gè)回顧。在Werkzeug庫——local模塊一文中,我們講解了werkzeug.local模塊中實(shí)現(xiàn)的三個(gè)類Local、LocalStack和LocalProxy。關(guān)于它們的概念和詳細(xì)介紹,可以查看上面的文章。這里,我們用一個(gè)例子來說明Flask中使用的一種數(shù)據(jù)結(jié)構(gòu)LocalStack。

  1. >>> from werkzeug.local import LocalStack 
  2.  
  3. >>> import threading 
  4.  
  5.   
  6.  
  7. # 創(chuàng)建一個(gè)`LocalStack`對象 
  8.  
  9. >>> local_stack = LocalStack() 
  10.  
  11. # 查看local_stack中存儲(chǔ)的信息 
  12.  
  13. >>> local_stack._local.__storage__ 
  14.  
  15. {} 
  16.  
  17.   
  18.  
  19. # 定義一個(gè)函數(shù),這個(gè)函數(shù)可以向`LocalStack`中添加數(shù)據(jù) 
  20.  
  21. >>> def worker(i): 
  22.  
  23.         local_stack.push(i) 
  24.  
  25.   
  26.  
  27. # 使用3個(gè)線程運(yùn)行函數(shù)`worker` 
  28.  
  29. >>> for i in range(3): 
  30.  
  31.         t = threading.Thread(target=worker, args=(i,)) 
  32.  
  33.         t.start() 
  34.  
  35.   
  36.  
  37. # 再次查看local_stack中存儲(chǔ)的信息 
  38.  
  39. >>> local_stack._local.__storage__ 
  40.  
  41. {<greenlet.greenlet at 0x4bee5a0>: {'stack': [2]}, 
  42.  
  43. <greenlet.greenlet at 0x4bee638>: {'stack': [1]}, 
  44.  
  45. <greenlet.greenlet at 0x4bee6d0>: {'stack': [0]} 
  46.  
  47.  

由上面的例子可以看出,存儲(chǔ)在LocalStack中的信息以字典的形式存在:鍵為線程/協(xié)程的標(biāo)識(shí)數(shù)值,值也是字典形式。每當(dāng)有一個(gè)線程/協(xié)程上要將一個(gè)對象push進(jìn)LocalStack棧中,會(huì)形成如上一個(gè)“鍵-值”對。這樣的一種結(jié)構(gòu)很好地實(shí)現(xiàn)了線程/協(xié)程的隔離,每個(gè)線程/協(xié)程都會(huì)根據(jù)自己線程/協(xié)程的標(biāo)識(shí)數(shù)值確定存儲(chǔ)在棧結(jié)構(gòu)中的值。

LocalStack還實(shí)現(xiàn)了push、pop、top等方法。其中top方法永遠(yuǎn)指向棧頂?shù)脑亍m數(shù)脑厥侵府?dāng)前線程/協(xié)程中***被推入棧中的元素,即local_stack._local.stack[-1](注意,是stack鍵對應(yīng)的對象中***被推入的元素)。

請求上下文

Flask中所有的請求處理都在“請求上下文”中進(jìn)行,在它設(shè)計(jì)之初便就有這個(gè)概念。由于0.9版本代碼比較復(fù)雜,這里還是以0.1版本的代碼為例進(jìn)行說明。本質(zhì)上這兩個(gè)版本的“請求上下文”的運(yùn)行原理沒有變化,只是新版本增加了一些功能,這點(diǎn)在后面再進(jìn)行解釋。

請求上下文——0.1版本

  1. # Flask v0.1 
  2.  
  3. class _RequestContext(object): 
  4.  
  5.     """The request context contains all request relevant information.  It is 
  6.  
  7.     created at the beginning of the request and pushed to the 
  8.  
  9.     `_request_ctx_stack` and removed at the end of it.  It will create the 
  10.  
  11.     URL adapter and request object for the WSGI environment provided. 
  12.  
  13.     ""
  14.  
  15.   
  16.  
  17.     def __init__(self, app, environ): 
  18.  
  19.         self.app = app 
  20.  
  21.         self.url_adapter = app.url_map.bind_to_environ(environ) 
  22.  
  23.         self.request = app.request_class(environ) 
  24.  
  25.         self.session = app.open_session(self.request) 
  26.  
  27.         self.g = _RequestGlobals() 
  28.  
  29.         self.flashes = None 
  30.  
  31.   
  32.  
  33.     def __enter__(self): 
  34.  
  35.         _request_ctx_stack.push(self) 
  36.  
  37.   
  38.  
  39.     def __exit__(self, exc_type, exc_value, tb): 
  40.  
  41.         # do not pop the request stack if we are in debug mode and an 
  42.  
  43.         # exception happened.  This will allow the debugger to still 
  44.  
  45.         # access the request object in the interactive shell. 
  46.  
  47.         if tb is None or not self.app.debug: 
  48.  
  49.             _request_ctx_stack.pop()  

由上面“請求上下文”的實(shí)現(xiàn)可知:

  • “請求上下文”是一個(gè)上下文對象,實(shí)現(xiàn)了__enter__和__exit__方法。可以使用with語句構(gòu)造一個(gè)上下文環(huán)境。
  • 進(jìn)入上下文環(huán)境時(shí),_request_ctx_stack這個(gè)棧中會(huì)推入一個(gè)_RequestContext對象。這個(gè)棧結(jié)構(gòu)就是上面講的LocalStack棧。
  • 推入棧中的_RequestContext對象有一些屬性,包含了請求的的所有相關(guān)信息。例如app、request、session、g、flashes。還有一個(gè)url_adapter,這個(gè)對象可以進(jìn)行URL匹配。
  • 在with語句構(gòu)造的上下文環(huán)境中可以進(jìn)行請求處理。當(dāng)退出上下文環(huán)境時(shí),_request_ctx_stack這個(gè)棧會(huì)銷毀剛才存儲(chǔ)的上下文對象。
  • 以上的運(yùn)行邏輯使得請求的處理始終在一個(gè)上下文環(huán)境中,這保證了請求處理過程不被干擾,而且請求上下文對象保存在LocalStack棧中,也很好地實(shí)現(xiàn)了線程/協(xié)程的隔離。

以下是一個(gè)簡單的例子:

  1. # example - Flask v0.1 
  2.  
  3. >>> from flask import Flask, _request_ctx_stack 
  4.  
  5. >>> import threading 
  6.  
  7. >>> app = Flask(__name__) 
  8.  
  9. # 先觀察_request_ctx_stack中包含的信息 
  10.  
  11. >>> _request_ctx_stack._local.__storage__ 
  12.  
  13. {} 
  14.  
  15.   
  16.  
  17. # 創(chuàng)建一個(gè)函數(shù),用于向棧中推入請求上下文 
  18.  
  19. # 本例中不使用`with`語句 
  20.  
  21. >>> def worker(): 
  22.  
  23.         # 使用應(yīng)用的test_request_context()方法創(chuàng)建請求上下文 
  24.  
  25.         request_context = app.test_request_context() 
  26.  
  27.         _request_ctx_stack.push(request_context) 
  28.  
  29.   
  30.  
  31. # 創(chuàng)建3個(gè)進(jìn)程分別執(zhí)行worker方法 
  32.  
  33. >>> for i in range(3): 
  34.  
  35.         t = threading.Thread(target=worker) 
  36.  
  37.         t.start() 
  38.  
  39.   
  40.  
  41. # 再觀察_request_ctx_stack中包含的信息 
  42.  
  43. >>> _request_ctx_stack._local.__storage__ 
  44.  
  45. {<greenlet.greenlet at 0x5e45df0>: {'stack': [<flask._RequestContext at 0x710c668>]}, 
  46.  
  47. <greenlet.greenlet at 0x5e45e88>: {'stack': [<flask._RequestContext at 0x7107f28>]}, 
  48.  
  49. <greenlet.greenlet at 0x5e45f20>: {'stack': [<flask._RequestContext at 0x71077f0>]} 
  50.  
  51.  

上面的結(jié)果顯示:_request_ctx_stack中為每一個(gè)線程創(chuàng)建了一個(gè)“鍵-值”對,每一“鍵-值”對中包含一個(gè)請求上下文對象。如果使用with語句,在離開上下文環(huán)境時(shí)棧中銷毀存儲(chǔ)的上下文對象信息。

請求上下文——0.9版本

在0.9版本中,F(xiàn)lask引入了“應(yīng)用上下文”的概念,這對“請求上下文”的實(shí)現(xiàn)有一定的改變。這個(gè)版本的“請求上下文”也是一個(gè)上下文對象。在使用with語句進(jìn)入上下文環(huán)境后,_request_ctx_stack會(huì)存儲(chǔ)這個(gè)上下文對象。不過與0.1版本相比,有以下幾點(diǎn)改變:

  • 請求上下文實(shí)現(xiàn)了push、pop方法,這使得對于請求上下文的操作更加的靈活;
  • 伴隨著請求上下文對象的生成并存儲(chǔ)在棧結(jié)構(gòu)中,F(xiàn)lask還會(huì)生成一個(gè)“應(yīng)用上下文”對象,而且“應(yīng)用上下文”對象也會(huì)存儲(chǔ)在另一個(gè)棧結(jié)構(gòu)中去。這是兩個(gè)版本***的不同。

我們先看一下0.9版本相關(guān)的代碼:

  1. # Flask v0.9 
  2.  
  3. def push(self): 
  4.  
  5.     """Binds the request context to the current context.""" 
  6.  
  7.     top = _request_ctx_stack.top 
  8.  
  9.     if top is not None and top.preserved: 
  10.  
  11.         top.pop() 
  12.  
  13.   
  14.  
  15.     # Before we push the request context we have to ensure that there 
  16.  
  17.     # is an application context. 
  18.  
  19.     app_ctx = _app_ctx_stack.top 
  20.  
  21.     if app_ctx is None or app_ctx.app != self.app: 
  22.  
  23.         app_ctx = self.app.app_context() 
  24.  
  25.         app_ctx.push() 
  26.  
  27.         self._implicit_app_ctx_stack.append(app_ctx) 
  28.  
  29.     else
  30.  
  31.         self._implicit_app_ctx_stack.append(None) 
  32.  
  33.   
  34.  
  35.     _request_ctx_stack.push(self) 
  36.  
  37.   
  38.  
  39.     self.session = self.app.open_session(self.request) 
  40.  
  41.     if self.session is None: 
  42.  
  43.         self.session = self.app.make_null_session()  

我們注意到,0.9版本的“請求上下文”的pop方法中,當(dāng)要將一個(gè)“請求上下文”推入_request_ctx_stack棧中的時(shí)候,會(huì)先檢查另一個(gè)棧_app_ctx_stack的棧頂是否存在“應(yīng)用上下文”對象或者棧頂?shù)?ldquo;應(yīng)用上下文”對象的應(yīng)用是否是當(dāng)前應(yīng)用。如果不存在或者不是當(dāng)前對象,F(xiàn)lask會(huì)自動(dòng)先生成一個(gè)“應(yīng)用上下文”對象,并將其推入_app_ctx_stack中。

我們再看離開上下文時(shí)的相關(guān)代碼:

  1. # Flask v0.9 
  2.  
  3. def pop(self, exc=None): 
  4.  
  5.     """Pops the request context and unbinds it by doing that.  This will 
  6.  
  7.     also trigger the execution of functions registered by the 
  8.  
  9.     :meth:`~flask.Flask.teardown_request` decorator. 
  10.  
  11.   
  12.  
  13.     .. versionchanged:: 0.9 
  14.  
  15.        Added the `exc` argument. 
  16.  
  17.     ""
  18.  
  19.     app_ctx = self._implicit_app_ctx_stack.pop() 
  20.  
  21.   
  22.  
  23.     clear_request = False 
  24.  
  25.     if not self._implicit_app_ctx_stack: 
  26.  
  27.         self.preserved = False 
  28.  
  29.         if exc is None: 
  30.  
  31.             exc = sys.exc_info()[1] 
  32.  
  33.         self.app.do_teardown_request(exc) 
  34.  
  35.         clear_request = True 
  36.  
  37.   
  38.  
  39.     rv = _request_ctx_stack.pop() 
  40.  
  41.     assert rv is self, 'Popped wrong request context.  (%r instead of %r)' 
  42.  
  43.         % (rv, self) 
  44.  
  45.   
  46.  
  47.     # get rid of circular dependencies at the end of the request 
  48.  
  49.     # so that we don't require the GC to be active. 
  50.  
  51.     if clear_request: 
  52.  
  53.         rv.request.environ['werkzeug.request'] = None 
  54.  
  55.   
  56.  
  57.     # Get rid of the app as well if necessary. 
  58.  
  59.     if app_ctx is not None: 
  60.  
  61.         app_ctx.pop(exc)  

上面代碼中的細(xì)節(jié)先不討論。注意到當(dāng)要離開以上“請求上下文”環(huán)境的時(shí)候,F(xiàn)lask會(huì)先將“請求上下文”對象從_request_ctx_stack棧中銷毀,之后會(huì)根據(jù)實(shí)際的情況確定銷毀“應(yīng)用上下文”對象。

以下還是以一個(gè)簡單的例子進(jìn)行說明:

  1. # example - Flask v0.9 
  2.  
  3. >>> from flask import Flask, _request_ctx_stack, _app_ctx_stack 
  4.  
  5. >>> app = Flask(__name__) 
  6.  
  7.   
  8.  
  9. # 先檢查兩個(gè)棧的內(nèi)容 
  10.  
  11. >>> _request_ctx_stack._local.__storage__ 
  12.  
  13. {} 
  14.  
  15. >>> _app_ctx_stack._local.__storage__ 
  16.  
  17. {} 
  18.  
  19.   
  20.  
  21. # 生成一個(gè)請求上下文對象 
  22.  
  23. >>> request_context = app.test_request_context() 
  24.  
  25. >>> request_context.push() 
  26.  
  27.   
  28.  
  29. # 請求上下文推入棧后,再次查看兩個(gè)棧的內(nèi)容 
  30.  
  31. >>> _request_ctx_stack._local.__storage__ 
  32.  
  33. {<greenlet.greenlet at 0x6eb32a8>: {'stack': [<RequestContext 'http://localhost/' [GET] of __main__>]}} 
  34.  
  35. >>> _app_ctx_stack._local.__storage__ 
  36.  
  37. {<greenlet.greenlet at 0x6eb32a8>: {'stack': [<flask.ctx.AppContext at 0x5c96a58>]}} 
  38.  
  39.   
  40.  
  41. >>> request_context.pop() 
  42.  
  43.   
  44.  
  45. # 銷毀請求上下文時(shí),再次查看兩個(gè)棧的內(nèi)容 
  46.  
  47. >>> _request_ctx_stack._local.__storage__ 
  48.  
  49. {} 
  50.  
  51. >>> _app_ctx_stack._local.__storage__ 
  52.  
  53. {}  

應(yīng)用上下文

上部分中簡單介紹了“應(yīng)用上下文”和“請求上下文”的關(guān)系。那什么是“應(yīng)用上下文”呢?我們先看一下它的類:

  1. class AppContext(object): 
  2.  
  3.     """The application context binds an application object implicitly 
  4.  
  5.     to the current thread or greenlet, similar to how the 
  6.  
  7.     :class:`RequestContext` binds request information.  The application 
  8.  
  9.     context is also implicitly created if a request context is created 
  10.  
  11.     but the application is not on top of the individual application 
  12.  
  13.     context. 
  14.  
  15.     ""
  16.  
  17.   
  18.  
  19.     def __init__(self, app): 
  20.  
  21.         self.app = app 
  22.  
  23.         self.url_adapter = app.create_url_adapter(None) 
  24.  
  25.   
  26.  
  27.         # Like request context, app contexts can be pushed multiple times 
  28.  
  29.         # but there a basic "refcount" is enough to track them. 
  30.  
  31.         self._refcnt = 0 
  32.  
  33.   
  34.  
  35.     def push(self): 
  36.  
  37.         """Binds the app context to the current context.""" 
  38.  
  39.         self._refcnt += 1 
  40.  
  41.         _app_ctx_stack.push(self) 
  42.  
  43.   
  44.  
  45.     def pop(self, exc=None): 
  46.  
  47.         """Pops the app context.""" 
  48.  
  49.         self._refcnt -= 1 
  50.  
  51.         if self._refcnt <= 0: 
  52.  
  53.             if exc is None: 
  54.  
  55.                 exc = sys.exc_info()[1] 
  56.  
  57.             self.app.do_teardown_appcontext(exc) 
  58.  
  59.         rv = _app_ctx_stack.pop() 
  60.  
  61.         assert rv is self, 'Popped wrong app context.  (%r instead of %r)' \ 
  62.  
  63.             % (rv, self) 
  64.  
  65.   
  66.  
  67.     def __enter__(self):  

由以上代碼可以看出:“應(yīng)用上下文”也是一個(gè)上下文對象,可以使用with語句構(gòu)造一個(gè)上下文環(huán)境,它也實(shí)現(xiàn)了push、pop等方法。“應(yīng)用上下文”的構(gòu)造函數(shù)也和“請求上下文”類似,都有app、url_adapter等屬性。“應(yīng)用上下文”存在的一個(gè)主要功能就是確定請求所在的應(yīng)用。

然而,以上的論述卻又讓人產(chǎn)生這樣的疑問:既然“請求上下文”中也包含app等和當(dāng)前應(yīng)用相關(guān)的信息,那么只要調(diào)用_request_ctx_stack.top.app或者魔法current_app就可以確定請求所在的應(yīng)用了,那為什么還需要“應(yīng)用上下文”對象呢?對于單應(yīng)用單請求來說,使用“請求上下文”確實(shí)就可以了。然而,F(xiàn)lask的設(shè)計(jì)理念之一就是多應(yīng)用的支持。當(dāng)在一個(gè)應(yīng)用的請求上下文環(huán)境中,需要嵌套處理另一個(gè)應(yīng)用的相關(guān)操作時(shí),“請求上下文”顯然就不能很好地解決問題了。如何讓請求找到“正確”的應(yīng)用呢?我們可能會(huì)想到,可以再增加一個(gè)請求上下文環(huán)境,并將其推入_request_ctx_stack棧中。由于兩個(gè)上下文環(huán)境的運(yùn)行是獨(dú)立的,不會(huì)相互干擾,所以通過調(diào)用_request_ctx_stack.top.app或者魔法current_app也可以獲得當(dāng)前上下文環(huán)境正在處理哪個(gè)應(yīng)用。這種辦法在一定程度上可行,但是如果對于第二個(gè)應(yīng)用的處理不涉及到相關(guān)請求,那也就無從談起“請求上下文”。

為了應(yīng)對這個(gè)問題,F(xiàn)lask中將應(yīng)用相關(guān)的信息單獨(dú)拿出來,形成一個(gè)“應(yīng)用上下文”對象。這個(gè)對象可以和“請求上下文”一起使用,也可以單獨(dú)拿出來使用。不過有一點(diǎn)需要注意的是:在創(chuàng)建“請求上下文”時(shí)一定要?jiǎng)?chuàng)建一個(gè)“應(yīng)用上下文”對象。有了“應(yīng)用上下文”對象,便可以很容易地確定當(dāng)前處理哪個(gè)應(yīng)用,這就是魔法current_app。在0.1版本中,current_app是對_request_ctx_stack.top.app的引用,而在0.9版本中current_app是對_app_ctx_stack.top.app的引用。

下面以一個(gè)多應(yīng)用的例子進(jìn)行說明:

  1. # example - Flask v0.9 
  2.  
  3. >>> from flask import Flask, _request_ctx_stack, _app_ctx_stack 
  4.  
  5. # 創(chuàng)建兩個(gè)Flask應(yīng)用 
  6.  
  7. >>> app = Flask(__name__) 
  8.  
  9. >>> app2 = Flask(__name__) 
  10.  
  11. # 先查看兩個(gè)棧中的內(nèi)容 
  12.  
  13. >>> _request_ctx_stack._local.__storage__ 
  14.  
  15. {} 
  16.  
  17. >>> _app_ctx_stack._local.__storage__ 
  18.  
  19. {} 
  20.  
  21. # 構(gòu)建一個(gè)app的請求上下文環(huán)境,在這個(gè)環(huán)境中運(yùn)行app2的相關(guān)操作 
  22.  
  23. >>> with app.test_request_context(): 
  24.  
  25.         print "Enter app's Request Context:" 
  26.  
  27.         print _request_ctx_stack._local.__storage__ 
  28.  
  29.         print _app_ctx_stack._local.__storage__ 
  30.  
  31.         print 
  32.  
  33.         with app2.app_context(): 
  34.  
  35.             print "Enter app2's App Context:" 
  36.  
  37.             print _request_ctx_stack._local.__storage__ 
  38.  
  39.             print _app_ctx_stack._local.__storage__ 
  40.  
  41.             print 
  42.  
  43.             # do something 
  44.  
  45.         print "Exit app2's App Context:" 
  46.  
  47.         print _request_ctx_stack._local.__storage__ 
  48.  
  49.         print _app_ctx_stack._local.__storage__ 
  50.  
  51.         print 
  52.  
  53. # Result 
  54.  
  55. Enter app's Request Context: 
  56.  
  57. {<greenlet.greenlet object at 0x000000000727A178>: {'stack': [<RequestContext 'http://localhost/' [GET] of __main__>]}} 
  58.  
  59. {<greenlet.greenlet object at 0x000000000727A178>: {'stack': [<flask.ctx.AppContext object at 0x0000000005DD0DD8>]}} 
  60.  
  61.   
  62.  
  63. Enter app2's App Context: 
  64.  
  65. {<greenlet.greenlet object at 0x000000000727A178>: {'stack': [<RequestContext 'http://localhost/' [GET] of __main__>]}} 
  66.  
  67. {<greenlet.greenlet object at 0x000000000727A178>: {'stack': [<flask.ctx.AppContext object at 0x0000000005DD0DD8>, <flask.ctx.AppContext object at 0x0000000007313198>]}} 
  68.  
  69.   
  70.  
  71. Exit app2's App Context 
  72.  
  73. {<greenlet.greenlet object at 0x000000000727A178>: {'stack': [<RequestContext 'http://localhost/' [GET] of __main__>]}} 
  74.  
  75. {<greenlet.greenlet object at 0x000000000727A178>: {'stack': [<flask.ctx.AppContext object at 0x0000000005DD0DD8>]}}  

在以上的例子中:

  • 我們首先創(chuàng)建了兩個(gè)Flask應(yīng)用app和app2;
  • 接著我們構(gòu)建了一個(gè)app的請求上下文環(huán)境。當(dāng)進(jìn)入這個(gè)環(huán)境中時(shí),這時(shí)查看兩個(gè)棧的內(nèi)容,發(fā)現(xiàn)兩個(gè)棧中已經(jīng)有了當(dāng)前請求的請求上下文對象和應(yīng)用上下文對象。并且棧頂?shù)脑囟际莂pp的請求上下文和應(yīng)用上下文;
  • 之后,我們再在這個(gè)環(huán)境中嵌套app2的應(yīng)用上下文。當(dāng)進(jìn)入app2的應(yīng)用上下文環(huán)境時(shí),兩個(gè)上下文環(huán)境便隔離開來,此時(shí)再查看兩個(gè)棧的內(nèi)容,發(fā)現(xiàn)_app_ctx_stack中推入了app2的應(yīng)用上下文對象,并且棧頂指向它。這時(shí)在app2的應(yīng)用上下文環(huán)境中,current_app便會(huì)一直指向app2;
  • 當(dāng)離開app2的應(yīng)用上下文環(huán)境,_app_ctx_stack棧便會(huì)銷毀app2的應(yīng)用上下文對象。這時(shí)查看兩個(gè)棧的內(nèi)容,發(fā)現(xiàn)兩個(gè)棧中只有app的請求的請求上下文對象和應(yīng)用上下文對象。
  • ***,離開app的請求上下文環(huán)境后,兩個(gè)棧便會(huì)銷毀app的請求的請求上下文對象和應(yīng)用上下文對象,棧為空。

與上下文對象有關(guān)的“全局變量”

在Flask中,為了更加方便地處理一些變量,特地提出了“全局變量”的概念。這些全局變量有:

  1. # Flask v0.9 
  2.  
  3. _request_ctx_stack = LocalStack() 
  4.  
  5. _app_ctx_stack = LocalStack() 
  6.  
  7. current_app = LocalProxy(_find_app) 
  8.  
  9. request = LocalProxy(partial(_lookup_object, 'request')) 
  10.  
  11. session = LocalProxy(partial(_lookup_object, 'session')) 
  12.  
  13. g = LocalProxy(partial(_lookup_object, 'g')) 
  14.  
  15.   
  16.  
  17. # 輔助函數(shù) 
  18.  
  19. def _lookup_object(name): 
  20.  
  21.     top = _request_ctx_stack.top 
  22.  
  23.     if top is None: 
  24.  
  25.         raise RuntimeError('working outside of request context'
  26.  
  27.     return getattr(topname
  28.  
  29.   
  30.  
  31.   
  32.  
  33. def _find_app(): 
  34.  
  35.     top = _app_ctx_stack.top 
  36.  
  37.     if top is None: 
  38.  
  39.         raise RuntimeError('working outside of application context'
  40.  
  41.     return top.app  

可以看出,F(xiàn)lask中使用的一些“全局變量”,包括current_app、request、session、g等都來自于上下文對象。其中current_app一直指向_app_ctx_stack棧頂?shù)?ldquo;應(yīng)用上下文”對象,是對當(dāng)前應(yīng)用的引用。而request、session、g等一直指向_request_ctx_stack棧頂?shù)?ldquo;請求上下文”對象,分別引用請求上下文的request、session和g。不過,從 Flask 0.10 起,對象 g 存儲(chǔ)在應(yīng)用上下文中而不再是請求上下文中。

另外一個(gè)問題,在形成這些“全局變量”的時(shí)候,使用了werkzeug.local模塊的LocalProxy類。之所以要用該類,主要是為了動(dòng)態(tài)地實(shí)現(xiàn)對棧頂元素的引用。如果不使用這個(gè)類,在生成上述“全局變量”的時(shí)候,它們因?yàn)橹赶驐m斣兀鴹m斣卮藭r(shí)為None,所以這些變量也會(huì)被設(shè)置為None常量。后續(xù)即使有上下文對象被推入棧中,相應(yīng)的“全局變量”也不會(huì)發(fā)生改變。為了動(dòng)態(tài)地實(shí)現(xiàn)對棧頂元素的引用,這里必須使用werkzeug.local模塊的LocalProxy類。

責(zé)任編輯:龐桂玉 來源: Python開發(fā)者
相關(guān)推薦

2012-12-31 10:01:34

SELinuxSELinux安全

2020-10-21 09:11:52

Spring Boot源碼分析代碼

2022-09-14 13:13:51

JavaScript上下文

2023-01-14 22:49:44

Flask線程請求

2023-06-28 08:08:06

Flask上下文生命周期

2025-04-07 01:02:00

GoAPI語言

2021-09-07 09:53:42

JavaScript變量提升

2022-09-15 08:01:14

繼承基礎(chǔ)設(shè)施基礎(chǔ)服務(wù)

2023-07-11 10:02:23

2012-07-18 11:39:18

ibmdw

2024-09-30 14:10:00

2017-12-17 17:01:23

限界上下文系統(tǒng)模型

2022-10-28 16:24:33

Context上下文鴻蒙

2025-03-18 08:14:05

2022-10-31 15:34:30

python裝飾器內(nèi)存泄漏

2022-04-24 15:37:26

LinuxCPU

2020-07-24 10:00:00

JavaScript執(zhí)行上下文前端

2021-07-26 07:47:36

Cpu上下文進(jìn)程

2025-06-06 08:00:00

上下文管理器Python開發(fā)

2024-03-14 08:11:45

模型RoPELlama
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 男人的天堂一级片 | 亚洲精品美女视频 | 亚洲男女视频在线观看 | 亚洲 一区| 黄色片免费看 | 日韩欧美一区二区三区四区 | 日本高清视频在线播放 | 免费观看黄a一级视频 | av网站在线免费观看 | 国产精品自拍视频网站 | 国产97色 | 亚洲精品乱码久久久久久9色 | 亚洲一二三区在线观看 | 国产精品成人在线播放 | 久久中文字幕视频 | 国产在线视频在线观看 | 91在线视频 | 日韩在线视频观看 | 美女在线一区二区 | 一级大片网站 | 天天操天天干天天爽 | 亚洲精品久久视频 | 欧美视频在线播放 | 亚洲精品久久久久久下一站 | 成人综合一区二区 | 欧美高清视频一区 | 日韩a视频 | 久久天堂网 | 国产精品久久久久久久久久了 | 91新视频| 日韩在线观看视频一区 | 亚州av| 欧美激情精品久久久久久变态 | 国产激情视频 | 国产亚洲精品精品国产亚洲综合 | 亚洲精品高清视频在线观看 | 日韩精品久久久 | 嫩草视频网 | 免费观看一级毛片视频 | 国产成人叼嘿视频在线观看 | 午夜影院在线观看免费 |