My Favorite Python One Liner Sucks🔗
Writing to a file in one line🔗
tl;dr it's now:
Python is full of one-liners.
One of my favorites has been:
It opens a file in write mode and writes some data or other text to that file, returning the amount of bytes written to the file.
Generally useful for saving a list of column names or people names or what have you.
No external libraries, and even no extra imports because
open() is a built-in function
But it leaves the file handle open...
Which may not be a problem in some usecases, but it can prevent other users or processes from moving or deleting the file. Google's Python style guide provides some more reasons, including wasting resources and preventing logical errors in code.
Of course the
with ... as ...: syntax from PEP 343 is great for this safe handling of a file object that has to be opened and closed.
It can be done in one line, but most prefer to break it up into 2. This is more awkward to use in a REPL doing ad-hoc work or notebook trying to conserve cell space
Comparing With and Without (With)🔗
Checking out the bytecode on a simplified
write, we can confirm that my favorite one-liner doesn't close the file, whereas the
with one-liner does.
(If you're not familiar with dis, it's the Python module for disassembling Python code into its C bytecode. Not always necessary, but will prove 100% whether 2 code snippets operate the same under the covers)
1 2 3 4 5 6 7 8
Definitely no calls to
What about in the with statement?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
The context manager takes a lot more steps to manage the call stack.
But there's no clear call to the
close() function, which is the other standard way of writing to a file and closing the handle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
open() function code lives here.
It's a wrapper around a FileIO object, whose
close method will use
os.close(), the low-level file closing method.
The FileIO inherits a context manager from IOBase that calls
close when exited, so we can be sure it'll get called.
Making the extra import is worth it for
Path object to get the following:
- Accurate path on any OS
- file open and close with
- Still a similar one-liner!
Does the disassembler tell us anything?
1 2 3 4 5 6 7
Not really, what about on the write_text method specifically?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
Well that's a whole lot to end up looking like the same bytecode as the
In fact, pathlib would have gotten away with it too if it weren't for that meddling source code to betray it!
We wind up calling the same with statement, but get a free assertion that our data is a valid string:
write_text() is just
with open()... under the covers.
Nevertheless, I prefer the
write_text() one-liner to the
with open() as f: ... one-liner out of respect for colons.
Created: June 7, 2023