The recommended learning video tutorial is: Python Flask Advanced Programming
By learning the source code of these excellent open source projects, you can not only broaden your horizons, but also improve your Python coding level.
This article will introduce the following extensions to Python dictionaries in turn:
- Storage encapsulates dictionary operations for convenience
- ImmutiDict once assigned, immutable dictionary
- CaseSentiveDict Key case-insensitive generic dictionary
1. Storage
1.1 The role of Storage
Storage is a simple encapsulation by the author of web.py in order to use dictionaries more conveniently. After the encapsulation is complete, you can access dictionary items either through the dot operator (da) or through Python's built-in method (d['a']). Obviously, after using Storage for encapsulation, accessing the dictionary can save many characters, which is the convenience provided by Storage.
1.2 Source code of Storage
The specific implementation of Storage is as follows. In order to facilitate everyone to feel the usage of Storage more intuitively, I have made a simple modification to the Storage document:
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 Implementation Analysis of Storage
The implementation of Storage is very simple, except for the __repr__ function provided for friendly display, it only contains three special functions related to attributes, namely __getattr__, __setattr__, __delattr__. Obviously, these three special functions are the special functions that implement the operation of adding, deleting, modifying and checking the dictionary. Storage intercepts these three operations and reapplies them to the built-in dictionary operations to provide a more convenient dictionary.
It can be seen that the implementation of Storage is very simple, but Storage is indeed a good teaching project: 1) You can use Storage to learn how to extend the built-in dictionary; 2) Use Storage to understand the application of Python's operator overloading.
2. ImmutableDict
ImmutableDict is an immutable dictionary implemented in werkzeug. werkzeug is a WSGI toolset and a dependency of Flask, implemented by the author of Flask. Flask is currently the most popular web framework (one?) in the Python ecosystem.
2.1 Use of ImmutableDict
The use of ImmutableDict is very simple and straightforward, that is, to create an immutable dictionary. Once the dictionary is successfully created, it can only be accessed, and no modification operations can be performed, nor can the elements in the dictionary be deleted. As follows:
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 Implementation of ImmutableDict
The implementation of ImmutableDict is as follows:
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__