Commit 21e944f2 authored by Raymond Hettinger's avatar Raymond Hettinger

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.
parent 4d0b9d35
...@@ -33,6 +33,10 @@ list = d.keys() # a list of all existing keys (slow!) ...@@ -33,6 +33,10 @@ list = d.keys() # a list of all existing keys (slow!)
d.close() # close it d.close() # close it
\end{verbatim} \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: Restrictions:
\begin{itemize} \begin{itemize}
......
...@@ -15,7 +15,13 @@ your own dictionary-like classes, which can inherit from ...@@ -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 them and override existing methods or add new ones. In this way one
can add new behaviors to dictionaries. 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}} \begin{classdesc}{UserDict}{\optional{initialdata}}
Class that simulates a dictionary. The instance's Class that simulates a dictionary. The instance's
...@@ -35,6 +41,23 @@ A real dictionary used to store the contents of the \class{UserDict} ...@@ -35,6 +41,23 @@ A real dictionary used to store the contents of the \class{UserDict}
class. class.
\end{memberdesc} \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} --- \section{\module{UserList} ---
Class wrapper for list objects} Class wrapper for list objects}
......
...@@ -60,3 +60,67 @@ class UserDict: ...@@ -60,3 +60,67 @@ class UserDict:
class IterableUserDict(UserDict): class IterableUserDict(UserDict):
def __iter__(self): def __iter__(self):
return iter(self.data) 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()))
...@@ -40,9 +40,11 @@ try: ...@@ -40,9 +40,11 @@ try:
except ImportError: except ImportError:
from StringIO import StringIO from StringIO import StringIO
import UserDict
__all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"] __all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]
class Shelf: class Shelf(UserDict.DictMixin):
"""Base class for shelf implementations. """Base class for shelf implementations.
This is initialized with a dictionary-like object. This is initialized with a dictionary-like object.
......
...@@ -381,6 +381,15 @@ Extension modules ...@@ -381,6 +381,15 @@ Extension modules
Library 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 - A new package, logging, implements the logging API defined by PEP
282. The code is written by Vinay Sajip. 282. The code is written by Vinay Sajip.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment