1 """A more or less complete user-defined wrapper around dictionary objects.""" 2 3 class UserDict: 4 def __init__(self, dict=None, **kwargs): 5 self.data = {} 6 if dict is not None: 7 self.update(dict) 8 if len(kwargs): 9 self.update(kwargs) 10 def __repr__(self): return repr(self.data) 11 def __cmp__(self, dict): 12 if isinstance(dict, UserDict): 13 return cmp(self.data, dict.data) 14 else: 15 return cmp(self.data, dict) 16 __hash__ = None # Avoid Py3k warning 17 def __len__(self): return len(self.data) 18 def __getitem__(self, key): 19 if key in self.data: 20 return self.data[key] 21 if hasattr(self.__class__, "__missing__"): 22 return self.__class__.__missing__(self, key) 23 raise KeyError(key) 24 def __setitem__(self, key, item): self.data[key] = item 25 def __delitem__(self, key): del self.data[key] 26 def clear(self): self.data.clear() 27 def copy(self): 28 if self.__class__ is UserDict: 29 return UserDict(self.data.copy()) 30 import copy 31 data = self.data 32 try: 33 self.data = {} 34 c = copy.copy(self) 35 finally: 36 self.data = data 37 c.update(self) 38 return c 39 def keys(self): return self.data.keys() 40 def items(self): return self.data.items() 41 def iteritems(self): return self.data.iteritems() 42 def iterkeys(self): return self.data.iterkeys() 43 def itervalues(self): return self.data.itervalues() 44 def values(self): return self.data.values() 45 def has_key(self, key): return key in self.data 46 def update(self, dict=None, **kwargs): 47 if dict is None: 48 pass 49 elif isinstance(dict, UserDict): 50 self.data.update(dict.data) 51 elif isinstance(dict, type({})) or not hasattr(dict, 'items'): 52 self.data.update(dict) 53 else: 54 for k, v in dict.items(): 55 self[k] = v 56 if len(kwargs): 57 self.data.update(kwargs) 58 def get(self, key, failobj=None): 59 if key not in self: 60 return failobj 61 return self[key] 62 def setdefault(self, key, failobj=None): 63 if key not in self: 64 self[key] = failobj 65 return self[key] 66 def pop(self, key, *args): 67 return self.data.pop(key, *args) 68 def popitem(self): 69 return self.data.popitem() 70 def __contains__(self, key): 71 return key in self.data 72 @classmethod 73 def fromkeys(cls, iterable, value=None): 74 d = cls() 75 for key in iterable: 76 d[key] = value 77 return d 78 79 class IterableUserDict(UserDict): 80 def __iter__(self): 81 return iter(self.data) 82 83 import _abcoll 84 _abcoll.MutableMapping.register(IterableUserDict) 85 86 87 class DictMixin: 88 # Mixin defining all dictionary methods for classes that already have 89 # a minimum dictionary interface including getitem, setitem, delitem, 90 # and keys. Without knowledge of the subclass constructor, the mixin 91 # does not define __init__() or copy(). In addition to the four base 92 # methods, progressively more efficiency comes with defining 93 # __contains__(), __iter__(), and iteritems(). 94 95 # second level definitions support higher levels 96 def __iter__(self): 97 for k in self.keys(): 98 yield k 99 def has_key(self, key): 100 try: 101 self[key] 102 except KeyError: 103 return False 104 return True 105 def __contains__(self, key): 106 return self.has_key(key) 107 108 # third level takes advantage of second level definitions 109 def iteritems(self): 110 for k in self: 111 yield (k, self[k]) 112 def iterkeys(self): 113 return self.__iter__() 114 115 # fourth level uses definitions from lower levels 116 def itervalues(self): 117 for _, v in self.iteritems(): 118 yield v 119 def values(self): 120 return [v for _, v in self.iteritems()] 121 def items(self): 122 return list(self.iteritems()) 123 def clear(self): 124 for key in self.keys(): 125 del self[key] 126 def setdefault(self, key, default=None): 127 try: 128 return self[key] 129 except KeyError: 130 self[key] = default 131 return default 132 def pop(self, key, *args): 133 if len(args) > 1: 134 raise TypeError, "pop expected at most 2 arguments, got "\ 135 + repr(1 + len(args)) 136 try: 137 value = self[key] 138 except KeyError: 139 if args: 140 return args[0] 141 raise 142 del self[key] 143 return value 144 def popitem(self): 145 try: 146 k, v = self.iteritems().next() 147 except StopIteration: 148 raise KeyError, 'container is empty' 149 del self[k] 150 return (k, v) 151 def update(self, other=None, **kwargs): 152 # Make progressively weaker assumptions about "other" 153 if other is None: 154 pass 155 elif hasattr(other, 'iteritems'): # iteritems saves memory and lookups 156 for k, v in other.iteritems(): 157 self[k] = v 158 elif hasattr(other, 'keys'): 159 for k in other.keys(): 160 self[k] = other[k] 161 else: 162 for k, v in other: 163 self[k] = v 164 if kwargs: 165 self.update(kwargs) 166 def get(self, key, default=None): 167 try: 168 return self[key] 169 except KeyError: 170 return default 171 def __repr__(self): 172 return repr(dict(self.iteritems())) 173 def __cmp__(self, other): 174 if other is None: 175 return 1 176 if isinstance(other, DictMixin): 177 other = dict(other.iteritems()) 178 return cmp(dict(self.iteritems()), other) 179 def __len__(self): 180 return len(self.keys()) 181