/Lib/UserDict.py

http://unladen-swallow.googlecode.com/ · Python · 179 lines · 160 code · 8 blank · 11 comment · 46 complexity · 98d829f316bf2086f6bb0021c5bfcadd MD5 · raw file

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