How would you rewrite this Python code?
Dustin King
Posted on May 26, 2018
I ran across this problem while writing some code for a challenge.
I have some code that I want to write to a particular file if a filename is provided, or standard output if not:
with (open(filename, 'w') if filename else sys.stdout) as file:
do_something(file)
That with
line is a bit long, and doesn't seem readable at a glance. I could put the open
outside the with
:
f = open(filename, 'w') if filename else sys.stdout
with f as file:
do_something(file)
The file should be closed when the with
is exited. I'm done with stdout
in this case, but I could just have well have wanted to use it for other things later on in the program. But the worst thing about this way of doing it seems to be that making a habit of using open
outside a with
expression could lead to forgetting to close files.
I could go the try/finally route:
try:
f = open(filename, 'w') if filename else sys.stdout
do_something(f)
finally:
if f is not sys.stdout:
f.close()
But this seems a bit verbose and reminds me too much of Java, which, as a rule of thumb, probably means it's not Pythonic.
I could write a context manager to hide the "check if it's stdout and close it" logic:
from contextlib import contextmanager
@contextmanager
def file_or_stdout(fname):
if fname:
f = open(fname, 'w')
yield f
f.close()
else:
yield sys.stdout
with file_or_stdout(filename) as file:
do_something(file)
This seems pretty clear, but it also might be overkill. I'm leaning toward this though, as it leaves the do_something
block plenty of room for clarity, and I could extract the file_or_stdout
function into a utility library so it's not cluttering up the file.
Any thoughts?
Posted on May 26, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.