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