Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 205
weronika Avatar asked Aug 28 '12 22:08

weronika


2 Answers

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

like image 70
jdi Avatar answered Oct 20 '22 00:10

jdi


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.

like image 29
patzm Avatar answered Oct 20 '22 01:10

patzm