source: trunk/essentials/dev-lang/python/Lib/shelve.py

Last change on this file was 3225, checked in by bird, 18 years ago

Python 2.5

File size: 7.4 KB
Line 
1"""Manage shelves of pickled objects.
2
3A "shelf" is a persistent, dictionary-like object. The difference
4with dbm databases is that the values (not the keys!) in a shelf can
5be essentially arbitrary Python objects -- anything that the "pickle"
6module can handle. This includes most class instances, recursive data
7types, and objects containing lots of shared sub-objects. The keys
8are ordinary strings.
9
10To summarize the interface (key is a string, data is an arbitrary
11object):
12
13 import shelve
14 d = shelve.open(filename) # open, with (g)dbm filename -- no suffix
15
16 d[key] = data # store data at key (overwrites old data if
17 # using an existing key)
18 data = d[key] # retrieve a COPY of the data at key (raise
19 # KeyError if no such key) -- NOTE that this
20 # access returns a *copy* of the entry!
21 del d[key] # delete data stored at key (raises KeyError
22 # if no such key)
23 flag = d.has_key(key) # true if the key exists; same as "key in d"
24 list = d.keys() # a list of all existing keys (slow!)
25
26 d.close() # close it
27
28Dependent on the implementation, closing a persistent dictionary may
29or may not be necessary to flush changes to disk.
30
31Normally, d[key] returns a COPY of the entry. This needs care when
32mutable entries are mutated: for example, if d[key] is a list,
33 d[key].append(anitem)
34does NOT modify the entry d[key] itself, as stored in the persistent
35mapping -- it only modifies the copy, which is then immediately
36discarded, so that the append has NO effect whatsoever. To append an
37item to d[key] in a way that will affect the persistent mapping, use:
38 data = d[key]
39 data.append(anitem)
40 d[key] = data
41
42To avoid the problem with mutable entries, you may pass the keyword
43argument writeback=True in the call to shelve.open. When you use:
44 d = shelve.open(filename, writeback=True)
45then d keeps a cache of all entries you access, and writes them all back
46to the persistent mapping when you call d.close(). This ensures that
47such usage as d[key].append(anitem) works as intended.
48
49However, using keyword argument writeback=True may consume vast amount
50of memory for the cache, and it may make d.close() very slow, if you
51access many of d's entries after opening it in this way: d has no way to
52check which of the entries you access are mutable and/or which ones you
53actually mutate, so it must cache, and write back at close, all of the
54entries that you access. You can call d.sync() to write back all the
55entries in the cache, and empty the cache (d.sync() also synchronizes
56the persistent dictionary on disk, if feasible).
57"""
58
59# Try using cPickle and cStringIO if available.
60
61try:
62 from cPickle import Pickler, Unpickler
63except ImportError:
64 from pickle import Pickler, Unpickler
65
66try:
67 from cStringIO import StringIO
68except ImportError:
69 from StringIO import StringIO
70
71import UserDict
72import warnings
73
74__all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]
75
76class Shelf(UserDict.DictMixin):
77 """Base class for shelf implementations.
78
79 This is initialized with a dictionary-like object.
80 See the module's __doc__ string for an overview of the interface.
81 """
82
83 def __init__(self, dict, protocol=None, writeback=False):
84 self.dict = dict
85 if protocol is None:
86 protocol = 0
87 self._protocol = protocol
88 self.writeback = writeback
89 self.cache = {}
90
91 def keys(self):
92 return self.dict.keys()
93
94 def __len__(self):
95 return len(self.dict)
96
97 def has_key(self, key):
98 return self.dict.has_key(key)
99
100 def __contains__(self, key):
101 return self.dict.has_key(key)
102
103 def get(self, key, default=None):
104 if self.dict.has_key(key):
105 return self[key]
106 return default
107
108 def __getitem__(self, key):
109 try:
110 value = self.cache[key]
111 except KeyError:
112 f = StringIO(self.dict[key])
113 value = Unpickler(f).load()
114 if self.writeback:
115 self.cache[key] = value
116 return value
117
118 def __setitem__(self, key, value):
119 if self.writeback:
120 self.cache[key] = value
121 f = StringIO()
122 p = Pickler(f, self._protocol)
123 p.dump(value)
124 self.dict[key] = f.getvalue()
125
126 def __delitem__(self, key):
127 del self.dict[key]
128 try:
129 del self.cache[key]
130 except KeyError:
131 pass
132
133 def close(self):
134 self.sync()
135 try:
136 self.dict.close()
137 except AttributeError:
138 pass
139 self.dict = 0
140
141 def __del__(self):
142 if not hasattr(self, 'writeback'):
143 # __init__ didn't succeed, so don't bother closing
144 return
145 self.close()
146
147 def sync(self):
148 if self.writeback and self.cache:
149 self.writeback = False
150 for key, entry in self.cache.iteritems():
151 self[key] = entry
152 self.writeback = True
153 self.cache = {}
154 if hasattr(self.dict, 'sync'):
155 self.dict.sync()
156
157
158class BsdDbShelf(Shelf):
159 """Shelf implementation using the "BSD" db interface.
160
161 This adds methods first(), next(), previous(), last() and
162 set_location() that have no counterpart in [g]dbm databases.
163
164 The actual database must be opened using one of the "bsddb"
165 modules "open" routines (i.e. bsddb.hashopen, bsddb.btopen or
166 bsddb.rnopen) and passed to the constructor.
167
168 See the module's __doc__ string for an overview of the interface.
169 """
170
171 def __init__(self, dict, protocol=None, writeback=False):
172 Shelf.__init__(self, dict, protocol, writeback)
173
174 def set_location(self, key):
175 (key, value) = self.dict.set_location(key)
176 f = StringIO(value)
177 return (key, Unpickler(f).load())
178
179 def next(self):
180 (key, value) = self.dict.next()
181 f = StringIO(value)
182 return (key, Unpickler(f).load())
183
184 def previous(self):
185 (key, value) = self.dict.previous()
186 f = StringIO(value)
187 return (key, Unpickler(f).load())
188
189 def first(self):
190 (key, value) = self.dict.first()
191 f = StringIO(value)
192 return (key, Unpickler(f).load())
193
194 def last(self):
195 (key, value) = self.dict.last()
196 f = StringIO(value)
197 return (key, Unpickler(f).load())
198
199
200class DbfilenameShelf(Shelf):
201 """Shelf implementation using the "anydbm" generic dbm interface.
202
203 This is initialized with the filename for the dbm database.
204 See the module's __doc__ string for an overview of the interface.
205 """
206
207 def __init__(self, filename, flag='c', protocol=None, writeback=False):
208 import anydbm
209 Shelf.__init__(self, anydbm.open(filename, flag), protocol, writeback)
210
211
212def open(filename, flag='c', protocol=None, writeback=False):
213 """Open a persistent dictionary for reading and writing.
214
215 The filename parameter is the base filename for the underlying
216 database. As a side-effect, an extension may be added to the
217 filename and more than one file may be created. The optional flag
218 parameter has the same interpretation as the flag parameter of
219 anydbm.open(). The optional protocol parameter specifies the
220 version of the pickle protocol (0, 1, or 2).
221
222 See the module's __doc__ string for an overview of the interface.
223 """
224
225 return DbfilenameShelf(filename, flag, protocol, writeback)
Note: See TracBrowser for help on using the repository browser.