request 明明是个全局名字,为什么每个请求读到的都是自己的?它的类型到底是什么?这篇把代理对象拆开,看它背后的 ContextVar,并测它的开销。
request type = LocalProxy 真实对象类型 = Request current_app type = LocalProxy 真实对象类型 = Flask g type = LocalProxy 真实对象类型 = _AppCtxGlobals session type = LocalProxy 真实对象类型 = SecureCookieSession isinstance(request, Request) = True | request.__class__ = Request | type(request) is Request = False request is request._get_current_object(): False | request == request._get_current_object(): True repr(request) = <Request 'http://localhost/p?x=1' [GET]> 请求之外 repr(request) = <LocalProxy unbound>
上一篇:Flask Request Context;下一篇:Context Local 与线程隔离。
flask.globals._cv_request: <ContextVar name='flask.request_ctx' at 0x10acf2f20> | 类型 ContextVar
werkzeug.local.LocalProxy.__init__ 里处理 ContextVar 的分支(原样):
elif isinstance(local, ContextVar):
def _get_current_object() -> T:
try:
obj = local.get()
except LookupError:
raise RuntimeError(unbound_message) from None
return get_name(obj)线程 0:request.path = /t0,真实 Request 对象 id = 16880 线程 1:request.path = /t1,真实 Request 对象 id = 18480 线程 2:request.path = /t2,真实 Request 对象 id = 66816 线程 3:request.path = /t3,真实 Request 对象 id = 68640 4 个线程看到的路径互不相同: True | 对象 id 互不相同: True
通过代理 request.path:242 ns/次;真实对象 .path:25 ns/次;约 9.8 倍
g.get("b", "默认") = 默认 | "a" in g = True | g.setdefault("c", 3) = 3 | g.pop("a") = 1 | list(g) = ['c']
g.missing → AttributeError: missing
repr(g) = <flask.g of 'demo5'>
自定义 app_ctx_globals_class 后 g.created = True | 类型 = MyG传代理: RuntimeError: Working outside of application context. This typically means that you 传真实对象: demo5