From 7994716b6bcaeca64f47b7b3ed4e411bb6afc415 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 15 Nov 2002 06:46:14 +0000 Subject: SF patch #520382: Expand shelve.py to have a full dictionary interface and add a mixin to UserDict.py to make it easier to implement a full dictionary interface. --- Doc/lib/libshelve.tex | 4 ++++ Doc/lib/libuserdict.tex | 25 ++++++++++++++++++- Lib/UserDict.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ Lib/shelve.py | 4 +++- Misc/NEWS | 9 +++++++ 5 files changed, 104 insertions(+), 2 deletions(-) diff --git a/Doc/lib/libshelve.tex b/Doc/lib/libshelve.tex index 76eaaf4..1e02c7b 100644 --- a/Doc/lib/libshelve.tex +++ b/Doc/lib/libshelve.tex @@ -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} diff --git a/Doc/lib/libuserdict.tex b/Doc/lib/libuserdict.tex index d665686..e01c546 100644 --- a/Doc/lib/libuserdict.tex +++ b/Doc/lib/libuserdict.tex @@ -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} diff --git a/Lib/UserDict.py b/Lib/UserDict.py index 91af83c..b6b36b2 100644 --- a/Lib/UserDict.py +++ b/Lib/UserDict.py @@ -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())) diff --git a/Lib/shelve.py b/Lib/shelve.py index ae8df3f..7a318a6 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -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. diff --git a/Misc/NEWS b/Misc/NEWS index 34f70b7..7a6b780 100644 --- 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. -- cgit v0.12