flask源码剖析之上下文全局变量

 

flask有四个线程级的全局变量,两个是程序上下文变量:current_app和g,另外两个是请求上下文变量:request和session.

 

这四个变量只有从flask.globals中导入才可以使用,即

from flask import current_app

from flask import g

from flask import request

from flask import session

 

但是使用不意味着有效,要想有效,导入后还要再push程序上下文变量和请求上下文变量:

1)利用flask.app中的app.app_context()或app.request_context()方法建立AppContext(app)实例或RequestContext(...)实例;

      app_ctx       = app.app_context()

      request_ctx = app.request_context(...)

 


 
  1. def app_context(self):

  2. """Binds the application only. For as long as the application is bound

  3. to the current context the :data:`flask.current_app` points to that

  4. application. An application context is automatically created when a

  5. request context is pushed if necessary.

  6.  
  7. Example usage::

  8.  
  9. with app.app_context():

  10. ...

  11.  
  12. .. versionadded:: 0.9

  13. """

  14. return AppContext(self)

  15.  
  16. def request_context(self, environ):

  17. """Creates a :class:`~flask.ctx.RequestContext` from the given

  18. environment and binds it to the current context. This must be used in

  19. combination with the `with` statement because the request is only bound

  20. to the current context for the duration of the `with` block.

  21.  
  22. Example usage::

  23.  
  24. with app.request_context(environ):

  25. do_something_with(request)

  26.  
  27. The object returned can also be used without the `with` statement

  28. which is useful for working in the shell. The example above is

  29. doing exactly the same as this code::

  30.  
  31. ctx = app.request_context(environ)

  32. ctx.push()

  33. try:

  34. do_something_with(request)

  35. finally:

  36. ctx.pop()

  37.  
  38. .. versionchanged:: 0.3

  39. Added support for non-with statement usage and `with` statement

  40. is now passed the ctx object.

  41.  
  42. :param environ: a WSGI environment

  43. """

  44. return RequestContext(self, environ)

 

 

2)调用1)中建立的实例相应的push()方法——flask.ctx中;

      app_ctx.push( )

or   request_ctx.push( )    ???这个好像不需要???P12   

确实不需要,因为这是系统自动帮我们完成的!!!!具体参见文章Flask request,g,session的实现原理

 


 
  1. class AppContext(object):

  2. """The application context binds an application object implicitly

  3. to the current thread or greenlet, similar to how the

  4. :class:`RequestContext` binds request information. The application

  5. context is also implicitly created if a request context is created

  6. but the application is not on top of the individual application

  7. context.

  8. """

  9.  
  10. def __init__(self, app):

  11. self.app = app

  12. self.url_adapter = app.create_url_adapter(None)

  13. self.g = app.app_ctx_globals_class()

  14.  
  15. # Like request context, app contexts can be pushed multiple times

  16. # but there a basic "refcount" is enough to track them.

  17. self._refcnt = 0

  18.  
  19. def push(self):

  20. """Binds the app context to the current context."""

  21. self._refcnt += 1

  22. _app_ctx_stack.push(self)

  23. appcontext_pushed.send(self.app)

  24.  
  25. ......


 

 

3)2)中的push()方法实际上就是利用LocalStack()的实例_app_ctx_stack或_request_ctx_stack的push()方法——入栈。因此我们可以使用flask创建n个web app,而不会错乱。

一个web app有很多个request和session信息,使用_request_ctx_stack保存。

 


 
  1. # -*- coding: utf-8 -*-

  2. """

  3. flask.globals

  4. ~~~~~~~~~~~~~

  5.  
  6. Defines all the global objects that are proxies to the current

  7. active context.

  8.  
  9. :copyright: (c) 2011 by Armin Ronacher.

  10. :license: BSD, see LICENSE for more details.

  11. """

  12.  
  13. from functools import partial

  14. from werkzeug.local import LocalStack, LocalProxy

  15.  
  16.  
  17. def _lookup_req_object(name):

  18. top = _request_ctx_stack.top

  19. if top is None:

  20. raise RuntimeError('working outside of request context')

  21. return getattr(top, name)

  22.  
  23.  
  24. def _lookup_app_object(name):

  25. top = _app_ctx_stack.top

  26. if top is None:

  27. raise RuntimeError('working outside of application context')

  28. return getattr(top, name)

  29.  
  30.  
  31. def _find_app():

  32. top = _app_ctx_stack.top

  33. if top is None:

  34. raise RuntimeError('working outside of application context')

  35. return top.app

  36.  
  37.  
  38. # context locals

  39.  
  40. _request_ctx_stack = LocalStack()

  41. _app_ctx_stack = LocalStack()

  42.  
  43. current_app = LocalProxy(_find_app)

  44. request = LocalProxy(partial(_lookup_req_object, 'request'))

  45. session = LocalProxy(partial(_lookup_req_object, 'session'))

  46. g = LocalProxy(partial(_lookup_app_object, 'g'))


4)因此,所谓的app_ctx.push()实质上是落实在LocalStack().push()即_app_ctx_stack.push()之上的!

 


可参考文章Flask request,g,session的实现原理

出处:https://blog.csdn.net/LANGQING12345/article/details/46740551

阅读更多

没有更多推荐了,返回首页