werkzeug之Local解析

来源:互联网 发布:mac 如何恢复苹果系统 编辑:程序博客网 时间:2024/05/20 08:22

werkzeug库的local模块实现了类似java中的线程变量,该模块有4个类Local,LocalStack,LocalManager,LocalProxy,我们一一分析

Local

class Local(object):    __slots__ = ('__storage__', '__ident_func__')    def __init__(self):        object.__setattr__(self, '__storage__', {})        object.__setattr__(self, '__ident_func__', get_ident)    def __iter__(self):        return iter(self.__storage__.items())    def __call__(self, proxy):        """Create a proxy for a name."""        return LocalProxy(self, proxy)    def __release_local__(self):        self.__storage__.pop(self.__ident_func__(), None)    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}    def __delattr__(self, name):        try:            del self.__storage__[self.__ident_func__()][name]        except KeyError:            raise AttributeError(name)
该类有两个关键参数:'__storage__', '__ident_func__',其中'__storage__'初始化为一个空字典:{},'__ident_func__'初始化为get_ident,get_iden()函数返回一个协程/线程ID。

从__setattr__方法实现可以看出,给Local添加属性时,以协程/线程ID为第一级key,以属性名称为第二级key来保存值。下面做个试验以加深理解:

>>> l = Local()>>> l.stack = 'request'>>> l.__storage__{8168: {'stack': 'request'}}>>>

LocalStack

class LocalStack(object):    def __init__(self):        self._local = Local()    def __release_local__(self):        self._local.__release_local__()    def _get__ident_func__(self):        return self._local.__ident_func__    def _set__ident_func__(self, value):        object.__setattr__(self._local, '__ident_func__', value)    __ident_func__ = property(_get__ident_func__, _set__ident_func__)    del _get__ident_func__, _set__ident_func__    def __call__(self):        def _lookup():            rv = self.top            if rv is None:                raise RuntimeError('object unbound')            return rv        return LocalProxy(_lookup)    def push(self, obj):        """Pushes a new item to the stack"""        rv = getattr(self._local, 'stack', None)        if rv is None:            self._local.stack = rv = []        rv.append(obj)        return rv    def pop(self):        """Removes the topmost item from the stack, will return the        old value or `None` if the stack was already empty.        """        stack = getattr(self._local, 'stack', None)        if stack is None:            return None        elif len(stack) == 1:            release_local(self._local)            return stack[-1]        else:            return stack.pop()    @property    def top(self):        """The topmost item on the stack.  If the stack is empty,        `None` is returned.        """        try:            return self._local.stack[-1]        except (AttributeError, IndexError):            return None

LocalStack类的内部以Local为基础实现的,只不过对外提供了push,pop方法类似于栈结构。LocalStack将新增的属性及其值添加到Local的stack属性中,并且stack类型是列表当然,从前面实验中可以看出,Local的stack属性最终是存放在__storage__字典里面,并且以协程/线程ID隔离开。

>>> ls = LocalStack()>>> ls.push(10)[10]>>> ls.push('test')[10, 'test']>>> ls._local.__storage__{5948: {'stack': [10, 'test']}}>>> ls.top'test'>>>


LocalProxy

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__)    @property    def __dict__(self):        try:            return self._get_current_object().__dict__        except RuntimeError:            raise AttributeError('__dict__')    def __repr__(self):        try:            obj = self._get_current_object()        except RuntimeError:            return '<%s unbound>' % self.__class__.__name__        return repr(obj)    def __bool__(self):        try:            return bool(self._get_current_object())        except RuntimeError:            return False    def __unicode__(self):        try:            return unicode(self._get_current_object())  # noqa        except RuntimeError:            return repr(self)    def __dir__(self):        try:            return dir(self._get_current_object())        except RuntimeError:            return []    def __getattr__(self, name):        if name == '__members__':            return dir(self._get_current_object())        return getattr(self._get_current_object(), name)    def __setitem__(self, key, value):        self._get_current_object()[key] = value    def __delitem__(self, key):        del self._get_current_object()[key]    if PY2:        __getslice__ = lambda x, i, j: x._get_current_object()[i:j]        def __setslice__(self, i, j, seq):            self._get_current_object()[i:j] = seq        def __delslice__(self, i, j):            del self._get_current_object()[i:j]    __setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v)    __delattr__ = lambda x, n: delattr(x._get_current_object(), n)
LocalProxy是对具体对象的代理