django 源码分析 - 自定义数据结构

django 自定义了一些数据结构,主要有 OrderedSet,MultiValueDict,ImmutableList,DictWrapper

0x01

OrderedSet

class OrderedSet(object):

    def __init__(self, iterable=None):
        self.dict = OrderedDict(((x, None) for x in iterable) if iterable else [])

    def add(self, item):
        self.dict[item] = None

    def remove(self, item):
        del self.dict[item]

    def discard(self, item):
        try:
            self.remove(item)
        except KeyError:
            pass

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

    def __contains__(self, item):
        return item in self.dict

    def __bool__(self):
        return bool(self.dict)

    def __nonzero__(self):      # Python 2 compatibility
        return type(self).__bool__(self)

    def __len__(self):
        return len(self.dict)

这里面最重要的其实就是 self.dict = OrderedDict(((x, None) for x in iterable) if iterable else []), 使用了 OrderedDict 有序字典 这个 python 标准库里面的数据结构,下面看下 self.dict 的返回形式

>>> from collections import OrderedDict
>>> iterable = [1,2,3]
>>> OrderedDict(((x, None) for x in iterable) if iterable else [])
OrderedDict([(1, None), (2, None), (3, None)])

0x02

MultiValueDict

MultiValueDict 在 http 请求参数处理的时候特别有用,因为有的时候传入的参数是一个数组,QueryDict 继承了 MultiValueDict, 来对参数进行处理,先贴下用法

    >>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
    >>> d['name']
    'Simon'
    >>> d.getlist('name')
    ['Adrian', 'Simon']
    >>> d.getlist('doesnotexist')
    []
    >>> d.getlist('doesnotexist', ['Adrian', 'Simon'])
    ['Adrian', 'Simon']
    >>> d.get('lastname', 'nonexistent')
    'nonexistent'
    >>> d.setlist('lastname', ['Holovaty', 'Willison'])

主要是实现了 getlist, setlist 方法, getlist 调用 getitem, getitem 当 key 不存在时,返回 []

def __getitem__(self, key):
        """
        Returns the last data value for this key, or [] if it's an empty list;
        raises KeyError if not found.
        """
        try:
            list_ = super(MultiValueDict, self).__getitem__(key)
        except KeyError:
            raise MultiValueDictKeyError(repr(key))
        try:
            return list_[-1]
        except IndexError:
            return []

0x03

ImmutableList

class ImmutableList(tuple):
    def __new__(cls, *args, **kwargs):
        if 'warning' in kwargs:
            warning = kwargs['warning']
            del kwargs['warning']
        else:
            warning = 'ImmutableList object is immutable.'
        self = tuple.__new__(cls, *args, **kwargs)
        self.warning = warning
        return self

    def complain(self, *wargs, **kwargs):
        if isinstance(self.warning, Exception):
            raise self.warning
        else:
            raise AttributeError(self.warning)

当这个数据结构的实例改变时,会提示一些有用的信息来提示用户这个类是不可变的

0x04

DictWrapper

主要是做了 dict 的封装

class DictWrapper(dict):
    def __init__(self, data, func, prefix):
        super(DictWrapper, self).__init__(data)
        self.func = func
        self.prefix = prefix
        
    def __getitem__(self, key):
        if key.startswith(self.prefix):
            use_func = True
            key = key[len(self.prefix):]
        else:
            use_func = False
        value = super(DictWrapper, self).__getitem__(key)
        if use_func:
            return self.func(value)
        return value

>>> def call_f(a):
...     return 'hello %s' % a
...
>> dict_wrapper = DictWrapper({'1': 'john'}, call_f, 'prefix_')
>>> dict_wrapper['prefix_1']
'hello john'

当出现 prefix 前缀时自动会去调用 func 返回结果

你可能感兴趣的:(django 源码分析 - 自定义数据结构)