Problem: How to defer the allocation of a file descriptor in Python?
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()