UserDict.py 5.58 KB
Newer Older
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 8 9
            self.update(dict)
        if len(kwargs):
            self.update(kwargs)
10 11
    def __repr__(self): return repr(self.data)
    def __cmp__(self, dict):
12
        if isinstance(dict, UserDict):
13
            return cmp(self.data, dict.data)
14 15
        else:
            return cmp(self.data, dict)
16
    def __len__(self): return len(self.data)
Guido van Rossum's avatar
Guido van Rossum committed
17 18 19 20 21 22
    def __getitem__(self, key):
        if key in self.data:
            return self.data[key]
        if hasattr(self.__class__, "__missing__"):
            return self.__class__.__missing__(self, key)
        raise KeyError(key)
23 24
    def __setitem__(self, key, item): self.data[key] = item
    def __delitem__(self, key): del self.data[key]
25
    def clear(self): self.data.clear()
26
    def copy(self):
27
        if self.__class__ is UserDict:
28
            return UserDict(self.data.copy())
29
        import copy
30 31 32 33 34 35 36 37
        data = self.data
        try:
            self.data = {}
            c = copy.copy(self)
        finally:
            self.data = data
        c.update(self)
        return c
38 39
    def keys(self): return self.data.keys()
    def items(self): return self.data.items()
40 41 42
    def iteritems(self): return self.data.iteritems()
    def iterkeys(self): return self.data.iterkeys()
    def itervalues(self): return self.data.itervalues()
43
    def values(self): return self.data.values()
44
    def has_key(self, key): return key in self.data
45 46 47 48
    def update(self, dict=None, **kwargs):
        if dict is None:
            pass
        elif isinstance(dict, UserDict):
49
            self.data.update(dict.data)
50
        elif isinstance(dict, type({})) or not hasattr(dict, 'items'):
51
            self.data.update(dict)
52
        else:
53
            for k, v in dict.items():
54
                self[k] = v
55 56
        if len(kwargs):
            self.data.update(kwargs)
57
    def get(self, key, failobj=None):
58
        if key not in self:
59 60
            return failobj
        return self[key]
61
    def setdefault(self, key, failobj=None):
62
        if key not in self:
63 64
            self[key] = failobj
        return self[key]
65 66
    def pop(self, key, *args):
        return self.data.pop(key, *args)
Guido van Rossum's avatar
Guido van Rossum committed
67 68
    def popitem(self):
        return self.data.popitem()
69 70
    def __contains__(self, key):
        return key in self.data
Guido van Rossum's avatar
Guido van Rossum committed
71
    @classmethod
72 73 74 75 76
    def fromkeys(cls, iterable, value=None):
        d = cls()
        for key in iterable:
            d[key] = value
        return d
77 78

class IterableUserDict(UserDict):
79 80
    def __iter__(self):
        return iter(self.data)
81 82

class DictMixin:
Raymond Hettinger's avatar
Raymond Hettinger committed
83 84 85 86
    # 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
Barry Warsaw's avatar
Barry Warsaw committed
87
    # methods, progressively more efficiency comes with defining
Raymond Hettinger's avatar
Raymond Hettinger committed
88
    # __contains__(), __iter__(), and iteritems().
89

Raymond Hettinger's avatar
Raymond Hettinger committed
90 91 92 93
    # second level definitions support higher levels
    def __iter__(self):
        for k in self.keys():
            yield k
94 95 96 97 98 99
    def has_key(self, key):
        try:
            value = self[key]
        except KeyError:
            return False
        return True
100 101
    def __contains__(self, key):
        return self.has_key(key)
102

Raymond Hettinger's avatar
Raymond Hettinger committed
103
    # third level takes advantage of second level definitions
104 105 106
    def iteritems(self):
        for k in self:
            yield (k, self[k])
107 108
    def iterkeys(self):
        return self.__iter__()
109

Raymond Hettinger's avatar
Raymond Hettinger committed
110
    # fourth level uses definitions from lower levels
111 112 113 114
    def itervalues(self):
        for _, v in self.iteritems():
            yield v
    def values(self):
Raymond Hettinger's avatar
Raymond Hettinger committed
115
        return [v for _, v in self.iteritems()]
116 117 118 119 120
    def items(self):
        return list(self.iteritems())
    def clear(self):
        for key in self.keys():
            del self[key]
121
    def setdefault(self, key, default=None):
Raymond Hettinger's avatar
Raymond Hettinger committed
122 123 124
        try:
            return self[key]
        except KeyError:
125
            self[key] = default
Raymond Hettinger's avatar
Raymond Hettinger committed
126
        return default
127 128 129 130 131 132 133 134 135 136
    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
137 138 139 140 141 142
        del self[key]
        return value
    def popitem(self):
        try:
            k, v = self.iteritems().next()
        except StopIteration:
Raymond Hettinger's avatar
Raymond Hettinger committed
143
            raise KeyError, 'container is empty'
144 145
        del self[k]
        return (k, v)
146
    def update(self, other=None, **kwargs):
Raymond Hettinger's avatar
Raymond Hettinger committed
147
        # Make progressively weaker assumptions about "other"
148 149 150
        if other is None:
            pass
        elif hasattr(other, 'iteritems'):  # iteritems saves memory and lookups
Raymond Hettinger's avatar
Raymond Hettinger committed
151 152
            for k, v in other.iteritems():
                self[k] = v
153
        elif hasattr(other, 'keys'):
Raymond Hettinger's avatar
Raymond Hettinger committed
154 155
            for k in other.keys():
                self[k] = other[k]
156 157 158 159 160
        else:
            for k, v in other:
                self[k] = v
        if kwargs:
            self.update(kwargs)
161
    def get(self, key, default=None):
Raymond Hettinger's avatar
Raymond Hettinger committed
162
        try:
163
            return self[key]
Raymond Hettinger's avatar
Raymond Hettinger committed
164 165
        except KeyError:
            return default
166
    def __repr__(self):
Raymond Hettinger's avatar
Raymond Hettinger committed
167 168
        return repr(dict(self.iteritems()))
    def __cmp__(self, other):
169 170
        if other is None:
            return 1
Raymond Hettinger's avatar
Raymond Hettinger committed
171 172 173 174 175
        if isinstance(other, DictMixin):
            other = dict(other.iteritems())
        return cmp(dict(self.iteritems()), other)
    def __len__(self):
        return len(self.keys())