]> granicus.if.org Git - python/commitdiff
SF patch #520382: Expand shelve.py to have a full dictionary interface
authorRaymond Hettinger <python@rcn.com>
Fri, 15 Nov 2002 06:46:14 +0000 (06:46 +0000)
committerRaymond Hettinger <python@rcn.com>
Fri, 15 Nov 2002 06:46:14 +0000 (06:46 +0000)
and add a mixin to UserDict.py to make it easier to implement a full
dictionary interface.

Doc/lib/libshelve.tex
Doc/lib/libuserdict.tex
Lib/UserDict.py
Lib/shelve.py
Misc/NEWS

index 76eaaf49c261fe0d344edbbbfc884115804e0304..1e02c7b5f68137ee73f1a35d031ffdb96bd0b26a 100644 (file)
@@ -33,6 +33,10 @@ list = d.keys() # a list of all existing keys (slow!)
 d.close()       # close it
 \end{verbatim}
 
+In addition to the above, shelve supports all methods that are
+supported by dictionaries.  This eases the transition from dictionary
+based scripts to those requiring persistent storage.
+
 Restrictions:
 
 \begin{itemize}
index d6656861e298a9c14d028ecacb3ea54320e9294d..e01c546c75e115743376288b55e9d2cea1b14983 100644 (file)
@@ -15,7 +15,13 @@ your own dictionary-like classes, which can inherit from
 them and override existing methods or add new ones.  In this way one
 can add new behaviors to dictionaries.
 
-The \module{UserDict} module defines the \class{UserDict} class:
+The module also defines a mixin defining all dictionary methods for
+classes that already have a minimum mapping interface.  This greatly
+simplifies writing classes that need to be substitutable for
+dictionaries (such as the shelve module).
+
+The \module{UserDict} module defines the \class{UserDict} class
+and \class{DictMixin}:
 
 \begin{classdesc}{UserDict}{\optional{initialdata}}
 Class that simulates a dictionary.  The instance's
@@ -35,6 +41,23 @@ A real dictionary used to store the contents of the \class{UserDict}
 class.
 \end{memberdesc}
 
+\begin{classdesc}{DictMixin}{}
+Mixin defining all dictionary methods for classes that already have
+a minimum dictionary interface including\method{__getitem__},
+\method{__setitem__}, \method{__delitem__}, and \method{keys}.
+
+This mixin should be used as a superclass.  Adding each of the
+above methods adds progressively more functionality.  For instance,
+the absence of \method{__delitem__} precludes only \method{pop}
+and \method{popitem}.
+
+While the four methods listed above are sufficient to support the
+entire dictionary interface, progessively more efficiency comes
+with defining \method{__contains__}, \method{__iter__}, and
+\method{iteritems}.
+
+\end{classdesc}
+
 
 \section{\module{UserList} ---
          Class wrapper for list objects}
index 91af83c08136495346daa97975e1bb2e650b1bb6..b6b36b2066b7ff382f355b098009ed56236172fc 100644 (file)
@@ -60,3 +60,67 @@ class UserDict:
 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 '''
+
+    # first level provided by subclass: getitem, setitem, delitem, and keys
+
+    # second level definitions which assume only getitem and keys
+    def has_key(self, key):
+        try:
+            value = self[key]
+        except KeyError:
+            return False
+        return True
+    __contains__ = has_key
+    def __iter__(self):
+        for k in self.keys():
+            yield k
+    def __len__(self):
+        return len(self.keys())
+
+    # third level uses second level instead of first
+    def iteritems(self):
+        for k in self:
+            yield (k, self[k])
+    iterkeys = __iter__
+
+    # fourth level uses second and third levels instead of first
+    def itervalues(self):
+        for _, v in self.iteritems():
+            yield v
+    def values(self):
+        return [self[key] for key in self.keys()]
+    def items(self):
+        return list(self.iteritems())
+    def clear(self):
+        for key in self.keys():
+            del self[key]
+    def setdefault(self, key, default):
+        if key not in self:
+            self[key] = default
+            return default
+        return self[key]
+    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, 'dictionary is empty'
+        del self[k]
+        return (k, v)
+    def update(self, other):
+        for key in other.keys():
+            self[key] = other[key]
+    def get(self, key, default=None):
+        if key in self:
+            return self[key]
+        return default
+    def __repr__(self):
+        return repr(dict(self.items()))
index ae8df3fc1ae84fcc4ca5d50f3dcf69cb01280b84..7a318a67ae8b8e5e4aad232d027d8bfe9d0a1f7e 100644 (file)
@@ -40,9 +40,11 @@ try:
 except ImportError:
     from StringIO import StringIO
 
+import UserDict
+
 __all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]
 
-class Shelf:
+class Shelf(UserDict.DictMixin):
     """Base class for shelf implementations.
 
     This is initialized with a dictionary-like object.
index 34f70b74744c445568208dab5866b00d5fe9bc57..7a6b78096070082ecabe0f711fbab5ed5edc7175 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -381,6 +381,15 @@ Extension modules
 Library
 -------
 
+- UserDict.py now defines a DictMixin class which defines all dictionary
+  methods for classes that already have a minimum mapping interface.
+  This greatly simplifies writing classes that need to be substitutable
+  for dictionaries (such as the shelve module).
+
+- shelve.py now subclasses from UserDict.DictMixin.  Now shelve supports
+  all dictionary methods.  This eases the transition to persistent
+  storage for scripts originally written with dictionaries in mind.                                                            
+
 - A new package, logging, implements the logging API defined by PEP
   282.  The code is written by Vinay Sajip.