The problem with an open statement, is that it immediately allocates the file descriptor (a commodity in limited supply).
Sometimes you want something else: a file object that you want to keep in store, and to be used later or not used at all. The file descriptor should be allocated only when actually opening the file and then it should be closed as soon as possible. The benefit is that you could have an unlimited supply of file objects (not filenames), without having to worry too much about allocated file descriptors.
Create a wrapper class that is a context manager. When creating the object express your intention to open the file (and how), without actually opening it.
# No file descriptor allocated:
f = FileWrapper('input.txt', 'w')
# The context manager opens and closes:
with f:
f.write("Hello world")
f.mode = 'r'
with f:
print(f.read())
class FileWrapper(object):
"""
A file object wrapper, that doesn't open a file descriptor
when created (only when explicitely opened, or in a with clause).
It is a useful pattern each time you want to prepare file objects that
will be read at a later time.
Usage
-----
f = FileWrapper('input.txt', 'r')
with f:
f.read()
"""
def __init__(self, filename, mode='r', *args, **kwargs):
self._filename = filename
self._file_object = None
self.mode = mode
self.args = args
self.kwargs = kwargs
@property
def mode(self):
"The open mode (writable property)"
return self._mode
@mode.setter
def mode(self, value):
self._mode = value
@property
def filename(self):
"The filename associated with the file"
return self._filename
def __enter__(self):
self.open(self.mode, *self.args, **self.kwargs)
return self
def __exit__(self, *args):
self._file_object.close()
def open(self, mode, *args, **kwargs):
"Open the file"
self._file_object = open(self.filename, mode, *args, **kwargs)
def read(self, *args, **kwargs):
"Read the contents of the file"
return self._file_object.read(*args, **kwargs)
def write(self, content, *args, **kwargs):
"Write into the file"
return self._file_object.write(content, *args, **kwargs)
def close(self):
"Close the file"
self._file_object.close()