推荐的学习视频教程是:Python Flask高级编程
通过学习这些优秀开源项目的源码,不但可以开阔自己视野,还能达到提高Python编码水平的目的。
本文将依次介绍以下几个对Python字典的扩展:
- Storage 封装字典操作提供便利性
- ImmutiDict 一旦赋值、不可修改的字典
- CaseSentiveDict Key大小写不敏感的通用字典
1. Storage
1.1 Storage的作用
Storage是web.py的作者为了更方便的使用字典,进行的简单封装。封装完成以后,既可以通过点运算符(d.a)访问字典的项,也可以通过Python内置的方式(d['a'])访问字典项。显然,使用Storage进行封装以后,访问字典可以少敲很多字符,这就是Storage提供的便利性。
1.2 Storage的源码
Storage的具体实现如下,为了便于大家更直观的感受Storage的用法,我对Storage的文档进行了简单修改:
class Storage(dict): """ A Storage object is like a dictionary except `obj.foo` can be used in addition to `obj['foo']`. o = Storage(a=1, b=2, c=3) >>> print o <Storage {'a': 1, 'c': 3, 'b': 2}> >>> o.a = 2 >>> print o <Storage {'a': 2, 'c': 3, 'b': 2}> >>> o.d = 4 >>> print o <Storage {'a': 2, 'c': 3, 'b': 2, 'd': 4}> >>> del o.b >>> print o <Storage {'a': 2, 'c': 3, 'd': 4}> >>> o.b Traceback (most recent call last): ... AttributeError: 'b' """ def __getattr__(self, key): try: return self[key] except KeyError as k: raise AttributeError(k) def __setattr__(self, key, value): self[key] = value def __delattr__(self, key): try: del self[key] except KeyError as k: raise AttributeError(k) def __repr__(self): return '<Storage ' + dict.__repr__(self) + '>'
1.3 Storage的实现解析
Storage的实现非常简单,除去为了友好的显示提供的__repr__函数以外,仅包含三个与属性相关的特殊函数,分别是__getattr__, __setattr__, __delattr__。显然,这三个特殊函数就是实现字典的增删改查操作的特殊函数。Storage拦截了这三个操作,并重新应用到内置字典的操作中,以此来提供一个操作更加方便的字典。
可以看到,Storage的实现非常简单,但是,Storage确是一个 很好的教学项目:1)可以通过Storage了解如何扩展内置字典;2)通过Storage了解Python的运算符重载的应用。
2. ImmutableDict
ImmutableDict是werkzeug中的实现的不可变字典。werkzeug是WSGI工具集,也是Flask的依赖,由Flask的作者实现。Flask是目前Python生态中最流行的Web框架(之一?)。
2.1 ImmutableDict的使用
ImmutableDict的使用很简单也很直接,就是创建一个不可修改的字典。字典一旦创建成功,就只能访问,不能进行任何修改操作,也不能删除字典中的元素。如下所示:
def main():
d = ImmutableDict(a=1, b=2, c=3) print(d) # ImmutableDict({'a': 1, 'c': 3, 'b': 2}) # d['d'] = 4 # TypeError: 'ImmutableDict' objects are immutable if __name__ == '__main__': main()
2.2 ImmutableDict的实现
ImmutableDict的实现如下:
from __future__ import print_function
def is_immutable(self): raise TypeError('%r objects are immutable' % self.__class__.__name__) class ImmutableDictMixin(object): """Makes a :class:`dict` immutable. .. versionadded:: 0.5 :private: """ _hash_cache = None @classmethod def fromkeys(cls, keys, value=None): instance = super(cls, cls).__new__(cls) instance.__init__(zip(keys, repeat(value))) return instance def __reduce_ex__(self, protocol): return type(self), (dict(self),) def _iter_hashitems(self): return iteritems(self) def __hash__(self): if self._hash_cache is not None: return self._hash_cache rv = self._hash_cache = hash(frozenset(self._iter_hashitems())) return rv def setdefault(self, key, default=None): is_immutable(self) def update(self, *args, **kwargs): is_immutable(self) def pop(self, key, default=None): is_immutable(self) def popitem(self): is_immutable(self) def __setitem__(self, key, value): is_immutable(self) def __delitem__(self, key): is_immutable(self) def clear(self): is_immutable(self) class ImmutableDict(ImmutableDictMixin, dict): """An immutable :class:`dict`. .. versionadded:: 0.5 """ def __repr__(self): return '%s(%s)' % ( self.__class__