Bottle中幾個有趣的類

DictPropery

    這個類的做用是將類中返回類字典對象的方法,變成一個read_only可控的屬性(描述符)。python

class Bottle(object):

    @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
    GET = query

class DictProperty(object):
    """ Property that maps to a key in a local dict-like attribute. """

    def __init__(self, attr, key=None, read_only=False):  # attr, key, read_only接收裝飾器的三個位置參數
        self.attr, self.key, self.read_only = attr, key, read_only

    def __call__(self, func):  # func接收類方法request.query
        functools.update_wrapper(self, func, updated=[])
        self.getter, self.key = func, self.key or func.__name__
        return self

    def __get__(self, obj, cls):  # 當訪問request.GET的時候,就會調用該方法, obj爲當前對象,cls爲當前類
        if obj is None: return self  # obj爲None說明被裝飾的方法做爲類變量來訪問(Bottle.query),返回描述符自身
        key, storage = self.key, getattr(obj, self.attr) 
        if key not in storage: storage[key] = self.getter(obj)  # 若是bottle.request.query不在storage也就是不在request.environ中的時候,在request.environ中添加'bottle.request.query':request.query(self), 即reqeuest.query(self)的返回值:GET參數的字典.
        return storage[key]

    def __set__(self, obj, value):  # 當request.GET被賦值時,調用__set__
        if self.read_only: raise AttributeError("Read-Only property.")  # raise read only
        getattr(obj, self.attr)[self.key] = value  # 在request.environ字典中添加一個'bottle.request.query':value。

    def __delete__(self, obj):  # 當該類方法被裝飾的方法別刪除是調用
        if self.read_only: raise AttributeError("Read-Only property.")
        del getattr(obj, self.attr)[self.key]  # 從request.environ字典中刪除bottle.request.query

    DictProperty這個類是一個裝飾器,也是一個描述符。能夠看出它其實是在操做,它的託管實例request的environ字典,當第一次訪問這個描述符的實例時,會把request.query(self)的結果放到environ這個字典裏。以後屢次訪問request.GET時,不用重複計算直接在environ中拿到結果。服務器

Bottle

class Bottle(object):

    def __call__(self, environ, start_response):  # 由於bottle__call__方法就是wsgi的協議函數,因此Bottle()實例就做爲了wsgi服務器的appliction函數
        """ Each instance of :class:'Bottle' is a WSGI application. """
        return self.wsgi(environ, start_response)

    def __enter__(self):  # return
        """ Use this application as default for all module-level shortcuts. """
        default_app.push(self)
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        default_app.pop()

    bottle實現了上下文管理器協議,因此你能夠像下面這樣寫,上下文管理器中的這個端點'/hello',不會受with塊外的那個同名端點影響。固然這兩個端點也不在一個Bottle實例上。。。。app

@route('/hello')
def greet(name):
    return HTTPResponse('hello2')

with Bottle() as b_app:
    @b_app.route('/hello')
    def hello():
        return HTTPResponse('hello')

    run(host='localhost', port='8888', debug=True, reloader=True)

MultiDict

    這個類實現了一個,value使用list存儲的字典 ,存儲重複 key 值時候 values 會以 list 形式都保存起來,默認返回list中最後一個value。ide

class MultiDict(DictMixin):
    """ This dict stores multiple values per key, but behaves exactly like a
        normal dict in that it returns only the newest value for any given key.
        There are special methods available to access the full list of values.
    """

    def __init__(self, *a, **k):
        self.dict = dict((k, [v]) for (k, v) in dict(*a, **k).items())

    def __delitem__(self, key):
        del self.dict[key]

    def __getitem__(self, key):
        return self.dict[key][-1]

    def __setitem__(self, key, value):
        self.append(key, value)

    def keys(self):
        return self.dict.keys()

    def get(self, key, default=None, index=-1, type=None):
        try:
            val = self.dict[key][index]
            return type(val) if type else val
        except Exception:
            pass
        return default

    def append(self, key, value):
        """ Add a new value to the list of values for this key. """
        self.dict.setdefault(key, []).append(value)

    def replace(self, key, value):
        """ Replace the list of values with a single value. """
        self.dict[key] = [value]

    def getall(self, key):
        """ Return a (possibly empty) list of values for a key. """
        return self.dict.get(key) or []

    #: Aliases for WTForms to mimic other multi-dict APIs (Django)
    getone = get
    getlist = getall

能夠探查一下 MultiDict生成對象的update 和 pop方法的行爲:函數

In [69]: dm = MultiDict()
In [70]: dm['a'] = 1
In [71]: dm['a'] = 2
In [72]: dm.getlist('a')
Out[72]: [1, 2]
In [73]: dm.update({'a':3})
In [74]: dm.getlist('a')
Out[74]: [1, 2, 3]
In [75]: dm.pop('a')
Out[75]: 3
In [76]: dm['a']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-76-54e5ceebc4de> in <module>()
----> 1 dm['a']
e:\py3env\lib\site-packages\bottle-0.13.dev0-py3.6.egg\bottle.py in __getitem__(self, key)
   2093
   2094     def __getitem__(self, key):
-> 2095         return self.dict[key][-1]
   2096
   2097     def __setitem__(self, key, value):
KeyError: 'a'

    MultiDict沒有重寫update方法爲何,使用update方法給更新key'a'的時候,會默認將value加到value list裏呢。由於update方法是的實現是經過操做dict[key]實現的。也就是使用了__getitem__, __setitem__, __delitem__方法。只要從新定製了這三個under方法,update就擁有如今的行爲。能夠定位到MutableMapping類中看一個update的實現。this

    FormsDict類繼承了MultiDict,因此有相似的行爲。spa

    HeaderDict類也繼承了MulticDict,不太重寫了__setitem__,__getitem__等方法,value仍是以list的形式存儲但只能有一個item。debug

In [85]: hd = HeaderDict()
In [86]: hd['a']='b'
In [87]: hd['a']='c'
In [89]: hd.getall('a')
Out[89]: ['c']

    HeaderDict的key在存取的時候使用str.title處理過,因此key是無關大小寫的,同時對key中的'-'和'_'也作了等效處理,也就是request.headers.get('CONTENT-LENGTH')和request.headers.get('content_length')等效。code

相關文章
相關標籤/搜索