Werkzeug源码阅读笔记(三)

这次主要讲下werkzeug中的Local. 源码在werkzeug/local.py

Thread Local

在Python中,状态是保存在对象中。Thread Local是一种特殊的对象,它是对线程隔离的。所谓对线程隔离,是指每一个线程对一个Thread Local对象进行修改,是不会影响到其他线程的。这就好比在工作单位每个人都有一个储物柜,每个人对自己的储物柜存取东西是不会影响到其他人的。这里的储物柜就是Thread Local.
获得一个Thread Local很简单,只需要对线程执行Local():threading.Local()
werkzeug的源码中,Local()类的实现比较简单,只是定义了几个特殊函数。文件在werkzeug/local.py
在该文件中,还定义了release_local(local)方法,用来释放local对象. 同时,在Local()类中实现了__release_local__()函数,它包裹了release_local(local)函数,调用__release_local__()可以释放当前Local对象

LocalStack

在werkzeug中同时实现了LocalStack这个类,它包含了Local()类的实例,实现了Local的栈结构,以下是重要部分的代码:

class LocalStack(object):
    def __init__(self):
        self._local = Local()			#LocalStack中有个Local类的对象

    def __release_local__(self):			#定义释放当前Local对象的方法
        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):
        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):
        try:
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None

所有对该对象的修改,只对本线程可见

LocalProxy

在werkzeug中还定义了本地代理。LocalProxy是典型的代理模式的实现。它在构造的时候接受一个callable的参数(实现了__call__()方法的类,一个函数等),这个参数被调用后的返回值本身是一个Thread Local对象。对一个LocalProxy对象的所有操作都会转发到那个callable参数返回的Thread Local对象上。
这是LocalProxy的初始化函数:

def __init__(self, local, name=None):
	object.__setattr__(self, '_LocalProxy__local', local)
	object.__setattr__(self, '__name__', name)

可以看到,该函数中有个local参数,这个参数就是callable参数。
下面是Local类中的__call__()函数

def __call__(self, proxy):
	"""Create a proxy for a name."""
	return LocalProxy(self, proxy)

比如执行:

l = Local()
request = l('request')

这时候就会调用__call__()函数,request = l('request')相当于执行:

request = LocalProxy(l, 'request')

这时候request就是一个LocalProxy对象,自动调用初始化函数,该对象有两个元素:_LocalProxy__local(等于l)和__name__(等于'request')
所以,对request的操作会返还给l进行实际操作
同时注意到LocalStack类也实现了__call__()函数,同样可以当做local参数.
LocalStack中的__call__函数:

def __call__(self):
	def _lookup():
		rv = self.top
		if rv is None:
			raise RuntimeError('object unbound')
		return rv
	return LocalProxy(_lookup)

执行:

_response_local = LocalStack()
response = _response_local()

这时候response就是一个LocalProxy,自动调用初始化函数,该对象有两个元素:_LocalProxy__local(等于_lookup函数)和__name__(等于None)

LocalProxy类中,还实现了一个重要的方法:_get_current_object():

def _get_current_object(self):
	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__)

这个方法的作用是获得该LocalProxy对象背后的真正的对象

LocalManager

在该文件中,还实现了LocalManager这个类. 因为Local对象不能管理自身,所以可能需要一个LocalManager对象,可以把多个Local对象传给LocalManager对象,该对象的每一次清理操作就会清理掉当前上下文中的Local对象
具体的类方法很简单,就不一一赘述了

posted @ 2015-06-30 22:38  Eric_Nirvana  阅读(1728)  评论(0编辑  收藏  举报