Reputation: 751
I really like the syntax "with open('in_file'') as f". I want to use that syntax for my own resources which must be opened and closed.
However, I do not understand how to change my open() method to enable the 'with' syntax. I can (and do) use the contextlib.closing() approach but it becomes a bit bulky after repeated use.
So, I will ask my question below in relation to shelve.open(). I am not proposing a change to the shelve module but instead am using it because the source code is readily available to all of you.
There is nothing special about shelve.open() vs. other standard library resources that require closing: socket.socket(), sqlite3.connect(), urllib2.urlopen(), etc.
import contextlib, inspect, shelve, sys
#print(inspect.getsource(open)) # can not see how it was done here :-(
print('-' * 40)
# Given that we can view the source for the shelve module:
print(inspect.getsource(shelve))
print('-' * 40)
# Given that we can view the docs for the shelve module:
print(shelve.__doc__)
#print('-' * 40)
# Given that the desired syntax is Pythonic but is not supported:
#with shelve.open('test_shelve') as my_shelve:
# my_shelve['fact_number_1'] = "There's a dead fish on the landing."
# Given that the required syntax is convoluted and
# takes programmer attention away from the task at hand:
with contextlib.closing(shelve.open('test_shelve')) as my_shelve:
my_shelve['fact_number_2'] = "There's another dead fish on the landing."
# Q: What changes would need to made to shelve.open() to allow the
# 'with shelve.open(x) as y' syntax?
I am not really interested in an extra wrapper with a different name. Using contextlib.closing() is easier, safer, and more intuitive than that. What I am really interested in is creating a single open() method that can be called either with or without 'with'.
So, to successfully answer this question, you need to take the source code for the shelve module and show what changes would need to be made to shelve.open() to have a single method that can be used either with or without 'with' (like the builtin open() or the Python3 urllib.urlopen()).
Upvotes: 2
Views: 290
Reputation: 280426
The biggest problem here is that if you do
shelf = the_function_you_want()
the function you want has to return the shelf, but if you do
with the_function_you_want() as shelf:
the function you want has to return a context manager. That means you need to return a shelf that is also a context manager, which in turn means you either need to make a shelf subclass or monkey-patch Shelf
. It's probably better to make a subclass:
class ContextManagerShelf(shelve.DbfilenameShelf):
def __enter__(self):
return self
def __exit__(self, *exc_info):
self.close()
Then you can use ContextManagerShelf
as a context manager or not. The signature is the same as shelve.open
. If you want, you can also make an open
function to go with it.
Upvotes: 2