pythonfile-iowith-statement

Is it possible to have an optional with/as statement in python?


Instead of this:

file = open(f)
do_something(file)
file.close()

it's better to use this:

with open(f) as file:
    do_something(file)

What if I have something like this?

if f is not None:
    file = open(f)
else:
    file = None
do_something(file)
if file is not None:
    file.close()

Where do_something also has an if file is None clause, and still does something useful in that case - I don't want to just skip do_something if file is None.

Is there a sensible way of converting this to with/as form? Or am I just trying to solve the optional file problem in a wrong way?


Solution

  • If you are using Python 3.7 or higher, then you can declare the null context manager for stand-in purposes in a much simpler way:

    import contextlib
    none_context = contextlib.nullcontext()
    

    You can read more about it here.


    if f is not None:
        with open(f) as FILE:
            do_something(FILE)
    else:
        do_something(f)
    

    Alternatively, here is a way to do an on-the-fly context with an optional None that won't crash:

    from contextlib import contextmanager
    
    none_context = contextmanager(lambda: iter([None]))()
    # <contextlib.GeneratorContextManager at 0x1021a0110>
    
    with (open(f) if f is not None else none_context) as FILE:
        do_something(FILE)
    

    It creates a context that returns a None value. The with will either produce FILE as a file object, or a None type. But the None type will have a proper __exit__.