mirror of
https://github.com/python/cpython
synced 2024-11-05 18:12:54 +00:00
8ddc176e2e
Replaced docstring with comments. Prevents subclass contamination. Added the missing __cmp__() method and a test for __cmp__(). Used try/except style in preference to has_key() followed by a look-up. Used iteritem() where possible to save creating a long key list and to save redundant lookups. Expanded .update() to look for the most helpful methods first and gradually work down to a mininum expected interface. Expanded documentation to be more clear on how to use the class.
141 lines
4.6 KiB
Python
141 lines
4.6 KiB
Python
"""A more or less complete user-defined wrapper around dictionary objects."""
|
|
|
|
class UserDict:
|
|
def __init__(self, dict=None):
|
|
self.data = {}
|
|
if dict is not None: self.update(dict)
|
|
def __repr__(self): return repr(self.data)
|
|
def __cmp__(self, dict):
|
|
if isinstance(dict, UserDict):
|
|
return cmp(self.data, dict.data)
|
|
else:
|
|
return cmp(self.data, dict)
|
|
def __len__(self): return len(self.data)
|
|
def __getitem__(self, key): return self.data[key]
|
|
def __setitem__(self, key, item): self.data[key] = item
|
|
def __delitem__(self, key): del self.data[key]
|
|
def clear(self): self.data.clear()
|
|
def copy(self):
|
|
if self.__class__ is UserDict:
|
|
return UserDict(self.data)
|
|
import copy
|
|
data = self.data
|
|
try:
|
|
self.data = {}
|
|
c = copy.copy(self)
|
|
finally:
|
|
self.data = data
|
|
c.update(self)
|
|
return c
|
|
def keys(self): return self.data.keys()
|
|
def items(self): return self.data.items()
|
|
def iteritems(self): return self.data.iteritems()
|
|
def iterkeys(self): return self.data.iterkeys()
|
|
def itervalues(self): return self.data.itervalues()
|
|
def values(self): return self.data.values()
|
|
def has_key(self, key): return self.data.has_key(key)
|
|
def update(self, dict):
|
|
if isinstance(dict, UserDict):
|
|
self.data.update(dict.data)
|
|
elif isinstance(dict, type(self.data)):
|
|
self.data.update(dict)
|
|
else:
|
|
for k, v in dict.items():
|
|
self[k] = v
|
|
def get(self, key, failobj=None):
|
|
if not self.has_key(key):
|
|
return failobj
|
|
return self[key]
|
|
def setdefault(self, key, failobj=None):
|
|
if not self.has_key(key):
|
|
self[key] = failobj
|
|
return self[key]
|
|
def pop(self, key):
|
|
return self.data.pop(key)
|
|
def popitem(self):
|
|
return self.data.popitem()
|
|
def __contains__(self, key):
|
|
return key in self.data
|
|
|
|
class IterableUserDict(UserDict):
|
|
def __iter__(self):
|
|
return iter(self.data)
|
|
|
|
class DictMixin:
|
|
# Mixin defining all dictionary methods for classes that already have
|
|
# a minimum dictionary interface including getitem, setitem, delitem,
|
|
# and keys. Without knowledge of the subclass constructor, the mixin
|
|
# does not define __init__() or copy(). In addition to the four base
|
|
# methods, progessively more efficiency comes with defining
|
|
# __contains__(), __iter__(), and iteritems().
|
|
|
|
# second level definitions support higher levels
|
|
def __iter__(self):
|
|
for k in self.keys():
|
|
yield k
|
|
def has_key(self, key):
|
|
try:
|
|
value = self[key]
|
|
except KeyError:
|
|
return False
|
|
return True
|
|
__contains__ = has_key
|
|
|
|
# third level takes advantage of second level definitions
|
|
def iteritems(self):
|
|
for k in self:
|
|
yield (k, self[k])
|
|
iterkeys = __iter__
|
|
|
|
# fourth level uses definitions from lower levels
|
|
def itervalues(self):
|
|
for _, v in self.iteritems():
|
|
yield v
|
|
def values(self):
|
|
return [v for _, v in self.iteritems()]
|
|
def items(self):
|
|
return list(self.iteritems())
|
|
def clear(self):
|
|
for key in self.keys():
|
|
del self[key]
|
|
def setdefault(self, key, default):
|
|
try:
|
|
return self[key]
|
|
except KeyError:
|
|
self[key] = default
|
|
return default
|
|
def pop(self, key):
|
|
value = self[key]
|
|
del self[key]
|
|
return value
|
|
def popitem(self):
|
|
try:
|
|
k, v = self.iteritems().next()
|
|
except StopIteration:
|
|
raise KeyError, 'container is empty'
|
|
del self[k]
|
|
return (k, v)
|
|
def update(self, other):
|
|
# Make progressively weaker assumptions about "other"
|
|
if hasattr(other, 'iteritems'): # iteritems saves memory and lookups
|
|
for k, v in other.iteritems():
|
|
self[k] = v
|
|
elif hasattr(other, '__iter__'): # iter saves memory
|
|
for k in other:
|
|
self[k] = other[k]
|
|
else:
|
|
for k in other.keys():
|
|
self[k] = other[k]
|
|
def get(self, key, default=None):
|
|
try:
|
|
return self[key]
|
|
except KeyError:
|
|
return default
|
|
def __repr__(self):
|
|
return repr(dict(self.iteritems()))
|
|
def __cmp__(self, other):
|
|
if isinstance(other, DictMixin):
|
|
other = dict(other.iteritems())
|
|
return cmp(dict(self.iteritems()), other)
|
|
def __len__(self):
|
|
return len(self.keys())
|