I'm trying to use the shelve module in python, and I'm trying to combine it with the "with" statement, but when trying to do that I get the following error:
with shelve.open('shelve', 'c') as shlv_file:
shlv_file['title'] = 'The main title of my app'
shlv_file['datatype'] = 'data type int32'
shlv_file['content'] = 'Lorem ipsum'
shlv_file['refs'] = '<htppsa: asda.com>'
print(shlv_file)
The following error is raised:
with shelve.open('shelve', 'c') as shlv_file:
AttributeError: DbfilenameShelf instance has no attribute '__exit__'
Although doing this way:
shlv_file = shelve.open('data/shelve', 'c')
shlv_file['title'] = 'The main title of my app'
shlv_file['datatype'] = 'data type int32'
shlv_file['content'] = 'Lorem ipsum'
shlv_file['refs'] = '<htppsa: asda.com>'
shlv_file.close()
shlv_file = shelve.open('data/shelve', 'c')
shlv_file['new_filed'] = 'bla bla bla'
print(shlv_file)
No error is raised, and the output is the one that is expected. What is the problem with the first syntax ? I was watching a python course in which the instructor uses the first version without any problems.
You need to understand what the purpose of with
is used for. It is basically used to automatically handle setup and cleanup of objects it is called with, provided those objects support the use of such setup and cleanup functions. In particular, the object for setup is the __enter__
function, and the teardown equivalent is the __exit__
function. Here's an example:
In [355]: class Foo():
...: def __enter__(self):
...: print("Start!")
...: return self
...: def __exit__(self, type, value, traceback):
...: print("End!")
...:
And, now instantiate an object of Foo
with with...as
:
In [356]: with Foo() as x:
...: print(x)
...:
Start!
<__main__.Foo object at 0x1097f5da0>
End!
As you see, with...as
will compulsorily call these setup/teardown methods, and if they're missing, an AttributeError
will be raised because an attempt to call a non-existent instance method is made.
It's the same with your shelve
object - it doesn't have an __exit__
method defined in its class, so using with
will not work.
According to the documentation, support for the context manager was added from version 3.4 and onwards. If the context manager does not work, that would mean your version is older.