My Favorite Python One Liner Sucks🔗
Writing to a file in one line🔗
tl;dr it's now:
Python | |
---|---|
Text Only | |
---|---|
1 |
|
Python | |
---|---|
Favorite One-Liner🔗
Python is full of one-liners.
One of my favorites has been:
Python | |
---|---|
Text Only | |
---|---|
1 |
|
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.
With Statement🔗
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
Python | |
---|---|
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)
Text Only | |
---|---|
1 2 3 4 5 6 7 8 |
|
Definitely no calls to close()
.
What about in the with statement?
Python | |
---|---|
Text Only | |
---|---|
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.
Python | |
---|---|
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
The 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.
Pathlib usage🔗
Making the extra import is worth it for Path
object to get the following:
- Accurate path on any OS
- file open and close with
write_text()
- Still a similar one-liner!
Text Only | |
---|---|
1 |
|
Does the disassembler tell us anything?
Python | |
---|---|
Text Only | |
---|---|
1 2 3 4 5 6 7 |
|
Not really, what about on the write_text method specifically?
Python | |
---|---|
Text Only | |
---|---|
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 with
statement...
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:
Python | |
---|---|
Conclusion🔗
Pathlib 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