diff options
-rw-r--r-- | Lib/anydbm.py | 51 | ||||
-rw-r--r-- | Lib/copy.py | 98 | ||||
-rw-r--r-- | Lib/shelve.py | 66 |
3 files changed, 169 insertions, 46 deletions
diff --git a/Lib/anydbm.py b/Lib/anydbm.py index 49e819b..d24efe7 100644 --- a/Lib/anydbm.py +++ b/Lib/anydbm.py @@ -1,9 +1,50 @@ -"""A generic interface to all dbm clones.""" +"""A generic interface to all dbm clones. + +Instead of + + import dbm + d = dbm.open(file, 'rw', 0666) + +use + + import anydbm + d = anydbm.open(file) + +The returned object is a dbm, gdbm or (on the Mac) dbmac object, +dependent on availability of the modules (tested in this order). + +It has the following interface (key and data are strings): + + d[key] = data # store data at key (may override data at + # existing key) + data = d[key] # retrieve data at key (raise KeyError if no + # such key) + del d[key] # delete data stored at key (raises KeyError + # if no such key) + flag = d.has_key(key) # true if the key exists + list = d.keys() # return a list of all existing keys (slow!) + +Future versions may change the order in which implementations are +tested for existence, add interfaces to other db-like implementations +(e.g. BSD Hash), and (in the presence of multiple implementations) +decide which module to use based upon the extension or contents of an +existing database file. + +The open function has an optional second argument. This can be set to +'r' to open the database for reading only. Don't pas an explicit 'w' +or 'rw' to open it for writing, as the different interfaces have +different interpretation of their mode argument if it isn't 'r'. +""" try: import dbm - def open(file, mode = 'rw'): - return dbm.open(file, mode, 0666) + def open(filename, mode = 'rw'): + return dbm.open(filename, mode, 0666) except ImportError: - import dbmac - open = dbmac.open + try: + import gdbm + def open(filename, mode = 'w'): + return gdbm.open(filename, mode, 0666) + except ImportError: + import dbmac + open = dbmac.open diff --git a/Lib/copy.py b/Lib/copy.py index fe4c4fb..966bfa2 100644 --- a/Lib/copy.py +++ b/Lib/copy.py @@ -1,49 +1,73 @@ -# Generic (shallow and deep) copying operations -# ============================================= -# -# The difference between shallow and deep copying is only relevant for -# compound objects (objects that contain other objects, like lists or class -# instances). -# -# - A shallow copy constructs a new compound object and then (to the extent -# possible) inserts *the same objects* into in that the original contains. -# -# - A deep copy constructs a new compound object and then, recursively, -# inserts *copies* into it of the objects found in the original. -# -# Two problems often exist with deep copy operations that don't exist with -# shallow copy operations: -# -# (a) recursive objects (compound objects that, directly or indirectly, -# contain a reference to themselves) may cause a recursive loop -# -# (b) because deep copy copies *everything* it may copy too much, e.g. -# administrative data structures that should be shared even between copies -# -# Python's deep copy operation avoids these problems by: -# -# (a) keeping a table of objects already copied during the current copying pass -# -# (b) letting user-defined classes override the copying operation or the set -# of components copied -# -# This version does not copy types like module, class, function, method, -# nor stack trace, stack frame, nor file, socket, window, nor array, -# nor any similar types. +"""\ +Generic (shallow and deep) copying operations +============================================= +Interface summary: + + import copy + + x = copy.copy(y) # make a shallow copy of y + x = copy.deepcopy(y) # make a deep copy of y + +For module specific errors, copy.Error is raised. + +The difference between shallow and deep copying is only relevant for +compound objects (objects that contain other objects, like lists or +class instances). + +- A shallow copy constructs a new compound object and then (to the + extent possible) inserts *the same objects* into in that the + original contains. + +- A deep copy constructs a new compound object and then, recursively, + inserts *copies* into it of the objects found in the original. + +Two problems often exist with deep copy operations that don't exist +with shallow copy operations: + +(a) recursive objects (compound objects that, directly or indirectly, + contain a reference to themselves) may cause a recursive loop + +(b) because deep copy copies *everything* it may copy too much, e.g. + administrative data structures that should be shared even between + copies + +Python's deep copy operation avoids these problems by: + +(a) keeping a table of objects already copied during the current +copying pass + +(b) letting user-defined classes override the copying operation or the + set of components copied + +This version does not copy types like module, class, function, method, +nor stack trace, stack frame, nor file, socket, window, nor array, nor +any similar types. + +Classes can use the same interfaces to control copying that they use +to control pickling: they can define methods called __getinitargs__(), +__getstate__() and __setstate__(). See the __doc__ string of module +"pickle" for information on these methods. +""" import types Error = 'copy.Error' def copy(x): + """Shallow copy operation on arbitrary Python objects. + + See the module's __doc__ string for more info. + """ + try: copierfunction = _copy_dispatch[type(x)] except KeyError: try: copier = x.__copy__ except AttributeError: - raise Error, "un(shallow)copyable object of type %s" % type(x) + raise Error, \ + "un(shallow)copyable object of type %s" % type(x) y = copier() else: y = copierfunction(x) @@ -100,6 +124,11 @@ d[types.InstanceType] = _copy_inst del d def deepcopy(x, memo = None): + """Deep copy operation on arbitrary Python objects. + + See the module's __doc__ string for more info. + """ + if memo is None: memo = {} d = id(x) @@ -111,7 +140,8 @@ def deepcopy(x, memo = None): try: copier = x.__deepcopy__ except AttributeError: - raise Error, "un-deep-copyable object of type %s" % type(x) + raise Error, \ + "un-deep-copyable object of type %s" % type(x) y = copier(memo) else: y = copierfunction(x, memo) diff --git a/Lib/shelve.py b/Lib/shelve.py index b90e641..a7f289f 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -1,9 +1,43 @@ -"""Manage shelves of pickled objects.""" +"""Manage shelves of pickled objects. + +A "shelf" is a persistent, dictionary-like object. The difference +with dbm databases is that the values (not the keys!) in a shelf can +be essentially arbitrary Python objects -- anything that the "pickle" +module can handle. This includes most class instances, recursive data +types, and objects containing lots of shared sub-objects. The keys +are ordinary strings. + +To summarize the interface (key is a string, data is an arbitrary +object): + + import shelve + d = shelve.open(filename) # open, with (g)dbm filename + + d[key] = data # store data at key (overwrites old data if + # using an existing key) + data = d[key] # retrieve data at key (raise KeyError if no + # such key) + del d[key] # delete data stored at key (raises KeyError + # if no such key) + flag = d.has_key(key) # true if the key exists + list = d.keys() # a list of all existing keys (slow!) + + d.close() # close it + +Dependent on the implementation, closing a persistent dictionary may +or may not be necessary to flush changes to disk. +""" import pickle import StringIO + class Shelf: + """Base class for shelf implementations. + + This is initialized with a dictionary-like object. + See the module's __doc__ string for an overview of the interface. + """ def __init__(self, dict): self.dict = dict @@ -18,7 +52,8 @@ class Shelf: return self.dict.has_key(key) def __getitem__(self, key): - return pickle.Unpickler(StringIO.StringIO(self.dict[key])).load() + f = StringIO.StringIO(self.dict[key]) + return pickle.Unpickler(f).load() def __setitem__(self, key, value): f = StringIO.StringIO() @@ -30,14 +65,31 @@ class Shelf: del self.dict[key] def close(self): - self.db.close() + if hasattr(self.db, 'close'): + self.db.close() self.db = None + def __del__(self): + self.close() + + class DbShelf(Shelf): + """Shelf implementation using the "anydbm" generic dbm interface. + + This is initialized with the filename for the dbm database. + See the module's __doc__ string for an overview of the interface. + """ - def __init__(self, file): + def __init__(self, filename): import anydbm - Shelf.__init__(self, anydbm.open(file)) + Shelf.__init__(self, anydbm.open(filename)) -def open(file): - return DbShelf(file) + +def open(filename): + """Open a persistent dictionary for reading and writing. + + Argument is the filename for the dbm database. + See the module's __doc__ string for an overview of the interface. + """ + + return DbShelf(filename) |