zoukankan      html  css  js  c++  java
  • 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对象
    具体的类方法很简单,就不一一赘述了

  • 相关阅读:
    servlet的提交
    servlet的doPost 和doGet和web文件结构
    helloServlet
    捕鱼达人
    The 2018 ACM-ICPC China JiangSu Provincial Programming Contest I. T-shirt
    ACM-ICPC 2017 Asia Urumqi A. Coins
    Nordic Collegiate Programming Contest 2015​ B. Bell Ringing
    变量
    hiho 1050 树的直径
    ACM-ICPC 2017 Asia Urumqi G. The Mountain
  • 原文地址:https://www.cnblogs.com/eric-nirnava/p/werkzeug3.html
Copyright © 2011-2022 走看看