''' Shelve_test2.py
use a dictionary object and module shelve
to create a 'persistent to file' dictionary

Python2 creates a single (24kb) file 'phonebook.slv'
Python3 creates 3 much smaller (about 1kb each) files:
  'phonebook.slv.dir'
  'phonebook.slv.dat'
  'phonebook.slv.bak'

Tested with Python27 and Python33  by vegaseat  04sep2013
'''

import shelve

# name shelve byte stream data file
# works with Python2 annd Python3
data_file = 'phonebook.slv'

# open existing shelve file or create new shelve file
sh = shelve.open(data_file)

# a simple dictionary of name:phone pairs
phonebook = {
'Andrew Parson': '880-6336',
'Emily Everett': '678-4346', 
'Peter Power': '765-8344',
'Lewis Lame': '112-2345'
}

# this will save all current phonebook data 
# the access key will be "myphone_dict" (you pick name)
sh["myphone_dict"] = phonebook

# do one more dictionary entry ...
phonebook['Ginger Roger'] = '123-4567'
# you can update and save again before you close
sh["myphone_dict"] = phonebook
# close when done
sh.close()

# testing ...
# open the shelve file again for further work
# remember the access key is "myphone_dict"
sh = shelve.open(data_file)
phonebook2 = sh["myphone_dict"]

# can add another dictionary entry
phonebook2['Larry Lark'] = '923-4568'

# save the current phonebook data to the shelve file 
sh["myphone_dict"] = phonebook2
# close when done
sh.close()

print('-'*30)

# test the contents ...
# retrieve the saved data from the file
sh = shelve.open('phonebook.slv')
phonebook3 = sh["myphone_dict"]

# print the contents
for name, phone in sorted(phonebook3.items()):
    print( "%-20s  %s" % (name, phone) )

print('-'*30)

# close when done
sh.close()

''' result ...
------------------------------
Andrew Parson         880-6336
Emily Everett         678-4346
Ginger Roger          123-4567
Larry Lark            923-4568
Lewis Lame            112-2345
Peter Power           765-8344
------------------------------
'''

For the sake of comparing tools, here is the same code written with the well known zodb module instead of shelve.

''' zodb_test.py
Use third party module ZODB (zope object database)
to create a 'persistent to file' dictionary

Python 2 and 3 create files
    'phonebook.fs'
    'phonebook.fs.index'
    'phonebook.fs.lock'
    'phonebook.fs.tmp'
The files are not compatible between Python 2 and 3.

Tested with Python27 and Python33 by Gribouillis 2013-Sep-05
'''

# There are a few more necessary imports with zodb
from ZODB.FileStorage import FileStorage
from ZODB.DB import DB
import transaction
from BTrees.OOBTree import OOBTree

# name zodb data file
data_file = 'phonebook.fs'

# open existing zodb storage file or create new file
storage = FileStorage(data_file)
db = DB(storage)
connection = db.open()
sh = connection.root() # <- our starting point, the database root object.

# create a persistent dictionary (technically a b-tree)
phonebook = sh["myphone_dict"] = OOBTree()

# update from an ordinary python dictionary
phonebook.update({
'Andrew Parson': '880-6336',
'Emily Everett': '678-4346', 
'Peter Power': '765-8344',
'Lewis Lame': '112-2345'
})

# do one more dictionary entry ...
phonebook['Ginger Roger'] = '123-4567'

# save to database before you close
transaction.commit()

# close when done. A few more calls than with shelves.
connection.close()
db.close()
storage.close()

# testing ...
# open the zodb file again for further work
# remember the access key is "myphone_dict"
storage = FileStorage(data_file)
db = DB(storage)
connection = db.open()
sh = connection.root()

phonebook2 = sh["myphone_dict"]

# can add another dictionary entry
phonebook2['Larry Lark'] = '923-4568'

# save before you close
transaction.commit()

# close when done
connection.close()
db.close()
storage.close()

print('-'*30)

# test the contents ...
# retrieve the saved data from the file
storage = FileStorage(data_file)
db = DB(storage)
connection = db.open()
sh = connection.root()

phonebook3 = sh["myphone_dict"]

# print the contents
for name, phone in sorted(phonebook3.items()):
    print( "%-20s  %s" % (name, phone) )

print('-'*30)

# close when done
connection.close()
db.close()
storage.close()

''' result ...
------------------------------
Andrew Parson         880-6336
Emily Everett         678-4346
Ginger Roger          123-4567
Larry Lark            923-4568
Lewis Lame            112-2345
Peter Power           765-8344
------------------------------
'''

Next step: comparative benchmarks :). Notice that zodb does not load the whole dictionary when it is accessed, because we chose the OOBTree class. It is suitable for very large data sets.

Edited 3 Years Ago by Gribouillis

The article starter has earned a lot of community kudos, and such articles offer a bounty for quality replies.