Skip to content

Instantly share code, notes, and snippets.

@fralau
Last active August 30, 2018 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fralau/98ec1afc1fe76390978224dd1014e6ea to your computer and use it in GitHub Desktop.
Save fralau/98ec1afc1fe76390978224dd1014e6ea to your computer and use it in GitHub Desktop.
Creating a file object, without immediately opening the file descriptor

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.

Idea

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())

Code

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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment