Often I need to output data either to file or, if file is not specified, to stdout. I use the following snippet:
if target:
with open(target, \'w\') as h
How about opening a new fd for sys.stdout? This way you won't have any problems closing it:
if not target:
target = "/dev/stdout"
with open(target, 'w') as f:
f.write(content)
if (out != sys.stdout):
with open(out, 'wb') as f:
f.write(data)
else:
out.write(data)
Slight improvement in some cases.
Another possible solution: do not try to avoid the context manager exit method, just duplicate stdout.
with (os.fdopen(os.dup(sys.stdout.fileno()), 'w')
if target == '-'
else open(target, 'w')) as f:
f.write("Foo")
The following solution is not a beauty, but from a time long, long ago; just before with ...
handler = open(path, mode = 'a') if path else sys.stdout
try:
print('stuff', file = handler)
... # other stuff or more writes/prints, etc.
except Exception as e:
if not (path is None): handler.close()
raise e
handler.close()
Okay, if we are getting into one-liner wars, here's:
(target and open(target, 'w') or sys.stdout).write(content)
I like Jacob's original example as long as context is only written in one place. It would be a problem if you end up re-opening the file for many writes. I think I would just make the decision once at the top of the script and let the system close the file on exit:
output = target and open(target, 'w') or sys.stdout
...
output.write('thing one\n')
...
output.write('thing two\n')
You could include your own exit handler if you think its more tidy
import atexit
def cleanup_output():
global output
if output is not sys.stdout:
output.close()
atexit(cleanup_output)
import contextlib
import sys
with contextlib.ExitStack() as stack:
h = stack.enter_context(open(target, 'w')) if target else sys.stdout
h.write(content)
Just two extra lines if you're using Python 3.3 or higher: one line for the extra import
and one line for the stack.enter_context
.