File indexing completed on 2024-04-14 15:48:36

0001 # -*- coding: UTF-8 -*-
0002 
0003 """
0004 Collections of multiple sequences.
0005 
0006 @author: Chusslove Illich (Часлав Илић) <caslav.ilic@gmx.net>
0007 @license: GPLv3
0008 """
0009 
0010 class Multidict (object):
0011     """
0012     Several dictionaries readable as one.
0013 
0014     Allows to get elements from several dictionary-like sequences
0015     as if they were one, without really creating a single union
0016     of items from all of them.
0017     This is useful when it is more expensive to create the union,
0018     than to look sequentially in each dictionary in turn.
0019 
0020     All methods named same as in C{dict} have same semantics too.
0021     """
0022 
0023     def __init__ (self, dicts):
0024         """
0025         Constructor.
0026 
0027         Order of dictionaries in the list matters,
0028         firstmost has highest priority when looking for a key.
0029 
0030         Collected sequences need to implement the following methods of
0031         a dictionary: C{__getitem__}, C{__contains__},
0032         C{iterkeys}, C{itervalues}, C{iteritems}.
0033         Iterators have to implement C{next} method,
0034         and raise C{StopIteration} when exhausted.
0035 
0036         @param dicts: sequence of dictionary-like objects
0037         @type dicts: list of dict
0038         """
0039 
0040         self._dicts = dicts
0041 
0042 
0043     def __contains__ (self, key):
0044 
0045         for d in self._dicts:
0046             if key in d:
0047                 return True
0048 
0049         return False
0050 
0051 
0052     def __getitem__ (self, key):
0053 
0054         for d in self._dicts:
0055             if key in d:
0056                 return d[key]
0057 
0058         raise KeyError(key)
0059 
0060 
0061     def __iter__ (self):
0062 
0063         return iter(self.keys())
0064 
0065 
0066     def get (self, key, defval=None):
0067 
0068         for d in self._dicts:
0069             if key in d:
0070                 return d[key]
0071 
0072         return defval
0073 
0074 
0075     def iterkeys (self):
0076 
0077         return self._Iterator(lambda x: iter(x.keys()))
0078 
0079 
0080     def itervalues (self):
0081 
0082         return self._Iterator(lambda x: iter(x.values()))
0083 
0084 
0085     def iteritems (self):
0086 
0087         return self._Iterator(lambda x: iter(x.items()))
0088 
0089 
0090     class _Iterator (object):
0091 
0092         def __init__ (self, getit):
0093             self._iters = [getit(d) for d in self._dicts]
0094 
0095         def __iter__ (self):
0096             return self
0097 
0098         def __next__ (self):
0099             while self._iters:
0100                 try:
0101                     return next(self._iters[0])
0102                 except StopIteration:
0103                     self._iters.pop(0)
0104             raise StopIteration
0105