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 class DictMixin: 84 # Mixin defining all dictionary methods for classes that already have 85 # a minimum dictionary interface including getitem, setitem, delitem, 86 # and keys. Without knowledge of the subclass constructor, the mixin 87 # does not define __init__() or copy(). In addition to the four base 88 # methods, progressively more efficiency comes with defining 89 # __contains__(), __iter__(), and iteritems(). 90 91 # second level definitions support higher levels 92 def __iter__(self): 93 for k in self.keys(): 94 yield k 95 def has_key(self, key): 96 try: 97 self[key] 98 except KeyError: 99 return False 100 return True 101 def __contains__(self, key): 102 return self.has_key(key) 103 104 # third level takes advantage of second level definitions 105 def iteritems(self): 106 for k in self: 107 yield (k, self[k]) 108 def iterkeys(self): 109 return self.__iter__() 110 111 # fourth level uses definitions from lower levels 112 def itervalues(self): 113 for _, v in self.iteritems(): 114 yield v 115 def values(self): 116 return [v for _, v in self.iteritems()] 117 def items(self): 118 return list(self.iteritems()) 119 def clear(self): 120 for key in self.keys(): 121 del self[key] 122 def setdefault(self, key, default=None): 123 try: 124 return self[key] 125 except KeyError: 126 self[key] = default 127 return default 128 def pop(self, key, *args): 129 if len(args) > 1: 130 raise TypeError, "pop expected at most 2 arguments, got "\ 131 + repr(1 + len(args)) 132 try: 133 value = self[key] 134 except KeyError: 135 if args: 136 return args[0] 137 raise 138 del self[key] 139 return value 140 def popitem(self): 141 try: 142 k, v = self.iteritems().next() 143 except StopIteration: 144 raise KeyError, 'container is empty' 145 del self[k] 146 return (k, v) 147 def update(self, other=None, **kwargs): 148 # Make progressively weaker assumptions about "other" 149 if other is None: 150 pass 151 elif hasattr(other, 'iteritems'): # iteritems saves memory and lookups 152 for k, v in other.iteritems(): 153 self[k] = v 154 elif hasattr(other, 'keys'): 155 for k in other.keys(): 156 self[k] = other[k] 157 else: 158 for k, v in other: 159 self[k] = v 160 if kwargs: 161 self.update(kwargs) 162 def get(self, key, default=None): 163 try: 164 return self[key] 165 except KeyError: 166 return default 167 def __repr__(self): 168 return repr(dict(self.iteritems())) 169 def __cmp__(self, other): 170 if other is None: 171 return 1 172 if isinstance(other, DictMixin): 173 other = dict(other.iteritems()) 174 return cmp(dict(self.iteritems()), other) 175 def __len__(self): 176 return len(self.keys())