What is Local
- wsgi each request, the process proceeds detached stateless will then process the data stored in the global variable in this request, used to Local. Local as a global command space for each request, each request is privately owned
- Local LocalStack and similar, used to operate in the stack mode Local basis, management
- LocalProxy proxy class, or Local Agent Examples LocalStack
Why Local
Why Custom Local, rather than threading.local. This is determined by the kernel
1. web after starting the application, is a single line + HS, then start the process, contaminate the global variables can not be distinguished,
2. HS + multithreading can not be guaranteed, the request distribution coroutine work, while the work can not be guaranteed and are respectively located in a plurality of threads, independent from other
So: werkzeug gives his own solution: Local and LocalStack
Why LocalProxy
So the question is: context of private variables to store the requested Local and LocalStack in that when multi-tasking, each call from flask import request, g, session, how to ensure get the correct context, and not chaos?
In flask.globals.py in
def _lookup_req_object(name): top = _request_ctx_stack.top if top is None: raise RuntimeError('working outside of request context') return getattr(top, name) _request_ctx_stack = LocalStack() request = LocalProxy(partial(_lookup_req_object, 'request')) session = LocalProxy(partial(_lookup_req_object, 'session'))
In werkzeug.local.py in, LocalProxy is an agent of a Local or LocalStack
@implements_bool class LocalProxy(object): """""" __slots__ = ("__local", "__dict__", "__name__", "__wrapped__") def __init__(self, local, name=None): object.__setattr__(self, "_LocalProxy__local", local) object.__setattr__(self, "__name__", name) if callable(local) and not hasattr(local, "__release_local__"): # "local" is a callable that is not an instance of Local or # LocalManager: mark it as a wrapped function. object.__setattr__(self, "__wrapped__", local) def _get_current_object(self): """Return the current object. This is useful if you want the real object behind the proxy at a time for performance reasons or because you want to pass the object into a different context. """ if not hasattr(self.__local, "__release_local__"): return self.__local() try: return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError("no object bound to %s" % self.__name__) def __getattr__(self, name): if name == "__members__": return dir(self._get_current_object()) return getattr(self._get_current_object(), name)
Call reqeust: Dynamic request <= dynamic _request_ctx_stack.top <= LocalStack () each time a new call instance be produced using methods and binding (request) <= LoaclStack.call?
Yes, each call request, it will generate a new proxy instance, every pop, push, top are for Local operation, and Local property assignment and acquisition are acquired for get_ident!
Such as: werkzeug.local.Local.py
class Local(object): __slots__ = ("__storage__", "__ident_func__") def __init__(self): object.__setattr__(self, "__storage__", {}) object.__setattr__(self, "__ident_func__", get_ident) """""" def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name) def __setattr__(self, name, value): ident = self.__ident_func__() storage = self.__storage__ try: storage[ident][name] = value except KeyError: storage[ident] = {name: value}
perfect! Every time a new request comes, will Flask werkzeug Local context stored in the thread obtained according to the use or id coroutine
What are the benefits of such use
- Supported by the underlying operating coroutine, improve the efficiency of concurrent expansion
- Management and avoid the application of the entire transfer request context
- Extended Compatibility perfect, to achieve a plug-in expansion of third-party applications
- Readability strong, simple operation, approachable