Question

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?

Was it helpful?

Solution

If you were to just write it like this:

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

(file is a builtin btw )

Update

Here is a funky 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__

Update

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 these here:

https://docs.python.org/3.7/library/contextlib.html#contextlib.nullcontext

OTHER TIPS

Since Python 3.7, you can also do

from contextlib import nullcontext

with (open(file) if file else nullcontext()) as FILE:
    # Do something with `FILE`
    pass

See the official documentation for more details.

This seems to solve all of your concerns.

if file_name is not None:
    with open(file_name) as fh:
        do_something(fh)
else:
        do_something(None)

something like:

if file:      #it checks for None,false values no need of "if file is None"
    with open(file) as FILE:
        do_something(FILE)
else:
    FILE=None

While all of the other answers are excellent, and preferable, note that the with expression may be any expression, so you can do:

with (open(file) if file is not None else None) as FILE:
    pass

Note that if the else clause were evaluated, to yield None this would result in an exception, because NoneType does not support the appropriate operations to be used as a context manager.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top