mirror of
https://github.com/python/cpython.git
synced 2024-12-01 05:45:40 +08:00
e4827eb2a2
Constructor accepts optional keyword arguments after a optional items list. Add fromkeys() as an alternate constructor from an iterable over keys. Expand related unittests.
153 lines
4.9 KiB
Python
153 lines
4.9 KiB
Python
"""A more or less complete user-defined wrapper around dictionary objects."""
|
|
|
|
class UserDict:
|
|
def __init__(self, dict=None, **kwargs):
|
|
self.data = {}
|
|
if dict is not None:
|
|
if not hasattr(dict,'keys'):
|
|
dict = type({})(dict) # make mapping from a sequence
|
|
self.update(dict)
|
|
if len(kwargs):
|
|
self.update(kwargs)
|
|
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
|
|
def fromkeys(cls, iterable, value=None):
|
|
d = cls()
|
|
for key in iterable:
|
|
d[key] = value
|
|
return d
|
|
fromkeys = classmethod(fromkeys)
|
|
|
|
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())
|