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 返回结果