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) # @实现的语法糖

 

posted @ 2017-10-30 11:59  fuzzier  阅读(987)  评论(0编辑  收藏  举报