bottle源码部分分析
这里主要参考 Rookie 的文章,里面用法很pythonic,所以来自己再分析一遍然后记笔记,详见原文 地址
我们这里只看 bottle 框架中的 request。所以我们看 BaseRquest(object) 类 和 BaseRequest 用到的描述器 DictProperty(object).
再看源码前,需要有以下知识点:
1. python 的 __call__(self[..) 方法
2 python 描述器 详见 地址 其中的描述器部分
3 python property 装饰器
下面分析源码
class DictProperty(object): ''' Property that maps to a key in a local dict-like attribute. ''' def __init__(self, attr, key=None, read_only=False): self.attr, self.key, self.read_only = attr, key, read_only def __call__(self, func): functools.update_wrapper(self, func, updated=[]) self.getter, self.key = func, self.key or func.__name__ return self def __get__(self, obj, cls): if obj is None: return self key, storage = self.key, getattr(obj, self.attr) if key not in storage: storage[key] = self.getter(obj) return storage[key] def __set__(self, obj, value): if self.read_only: raise AttributeError("Read-Only property.") getattr(obj, self.attr)[self.key] = value def __delete__(self, obj): if self.read_only: raise AttributeError("Read-Only property.") del getattr(obj, self.attr)[self.key]
class BaseRequest(object): # ... def __init__(self, environ=None): """ Wrap a WSGI environ dictionary. """ #: The wrapped WSGI environ dictionary. This is the only real attribute. #: All other attributes actually are read-only properties. self.environ = {} if environ is None else environ self.environ['bottle.request'] = self # ... @DictProperty('environ', 'bottle.request.query', read_only=True) def query(self): ''' The :attr:`query_string` parsed into a :class:`FormsDict`. These values are sometimes called "URL arguments" or "GET parameters", but not to be confused with "URL wildcards" as they are provided by the :class:`Router`. ''' get = self.environ['bottle.get'] = FormsDict() pairs = _parse_qsl(self.environ.get('QUERY_STRING', '')) for key, value in pairs: get[key] = value return get # ...
现在来看这个方法,从注释中我们知道,query 方法的逻辑是
先对 environ 新建了一个key 和 value,其中 valuie 是 dict 的衍生品 FormDict 对象。
然后 利用 _parser_qsl 方法将 get 请求中的 params 参数拿到,然后对 environ['bottle.get'] 进行添加 dict 类似的 key-value.。
最后 返回 environ['bottle.get'] 的 FormDict 对象。
下面是对 装饰器 @DictProperty('environ', 'bottle.request.query', read_only=True) 的分析
首先 这个 DictProperty 类是描述器的形式
然后 通过 然后通过 __call__ 方法 实现装饰器功能,在最后返回 DictProperty() 对象自己。
@DictProperty 结合 Baserequest().query() 的处理逻辑是
先明确一下 在 DictPropety 类中 self 是它自身的对象,也就是 DictPRoperty() 对象; 而 obj 则是调用者的对象,也就是里面的 Baserequest() 对象
首先 启动 bottle.py 时候, 运行到 @DictProperty('environ', 'bottle.request.query', read_only=True) , DictProperty 的 __init__ 和 __call__ 就会先后运行,所以 __call__ 执行后会返回 DictProperty() 的对象
然后调用 Baserequest().query() 方法时候,由于使用描述器的缘故,所以直接跳到 DictPRoperty().__get__(self, obj, owner) 方法上
现在我们主要看 DictPRoperty().__get__(self, obj, owner) 方法,其主要逻辑是:
先将 self,key 和 从 Baserequest()中取出的 environ, 分别赋值给变量 key 和 storage. 对象代码 key, storage = self.key, getattr(obj, self.attr)
然后 判断 key 是否已经存在在 environ 中(相当于@property),如果不存在就将 key-value 赋值,这里的 value 就是 obj.query() 方法 对应代码: if key not in storage: storage[key] = self.getter(obj)
最后 返回 envrion[key]
然后执行我们的 Baserequest().query() 逻辑。
将装饰器拆开分析
@DictProperty('environ', 'bottle.get.query', read_only=True) def query(self): """ some codes """
property = DictProperty('environ', 'bottle.get.query', read_only=True) @property def query(self): """ some codes """
描述器中的 __set__(self, obj) 已经实现了property 的功能
再来拆开语法糖 @
property = DictProperty('environ', 'bottle.get.query', read_only=True) query = property(query) # @实现的语法糖