You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
5.3 KiB
164 lines
5.3 KiB
"""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, *args): |
|
return self.data.pop(key, *args) |
|
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, progressively 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 |
|
def __contains__(self, key): |
|
return self.has_key(key) |
|
|
|
# third level takes advantage of second level definitions |
|
def iteritems(self): |
|
for k in self: |
|
yield (k, self[k]) |
|
def iterkeys(self): |
|
return self.__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, *args): |
|
if len(args) > 1: |
|
raise TypeError, "pop expected at most 2 arguments, got "\ |
|
+ repr(1 + len(args)) |
|
try: |
|
value = self[key] |
|
except KeyError: |
|
if args: |
|
return args[0] |
|
raise |
|
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 other is None: |
|
return 1 |
|
if isinstance(other, DictMixin): |
|
other = dict(other.iteritems()) |
|
return cmp(dict(self.iteritems()), other) |
|
def __len__(self): |
|
return len(self.keys())
|
|
|