Search code examples
pythonshelve

Why can't I store in a shelf file a dictionary that stores objects?


I'm using a dictionary to store objects. The dictionary is then stored in a shelf file. When retrieving the dictionary from the shelf file for printing stuff, it gets an error.

The following script is to creat a shelf file for testing:

# creating shelf file for testing
import shelve
class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

buddy = Dog("Buddy", 9)
miles = Dog("Miles", 4)
d = {}
d['buddy'] = buddy
d['miles'] = miles
with shelve.open('dogs') as sf:
    sf['d'] = d

Then, the following script reads the shelf file created above:

# reading shelf file and printing stuff

import shelve
with shelve.open('dogs') as sf:
    d = sf['d']

for k in d.keys():
    print(d[k].name, d[k].age)

After running the above script, it gets the following error message:

Traceback (most recent call last):
  File "C:\Users\jc\AppData\Local\Programs\Python\Python39\lib\shelve.py", line 111, in __getitem__
    value = self.cache[key]
KeyError: 'd'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\Users\jc\OneDrive\Documents\PythonScripts\test2.py", line 23, in <module>
    d = sf['d']
  File "C:\Users\jc\AppData\Local\Programs\Python\Python39\lib\shelve.py", line 114, in __getitem__
    value = Unpickler(f).load()
AttributeError: Can't get attribute 'Dog' on <module '__main__' from 'c:\\Users\\jc\\OneDrive\\Documents\\PythonScripts\\test2.py'>

Solution

  • The problem is that the script that reads the saved shelf doesn't know the definition of the Dog class.

    shelve is based on the pickle module. pickle can serialize instances of classes, but it doesn't serialize the class itself. The class definition must exist in the module that reads the shelved data.

    To quote the documentation:

    pickle can save and restore class instances transparently, however the class definition must be importable and live in the same module as when the object was stored.

    If you make sure the definition of Dog is available in the script before reading the shelf, the saved data will load correctly.