If I want to use a file
object just once, normally I would still use the with
block or explicitly close the file
object when I'm done, because closing a file seems to be the right-thing-to-do:
with open('filename','r') as f:
x = dosomething(f)
or
f = open('filename','r')
x = dosomething(f)
f.close()
However, I've seen people use pass the call to open
directly to a function without saving the output to any variable, making it impossible to close explicitly:
x = dosomething(open('filename','r'))
So, is either of these true,
or is this a bad practice?
Also, does the answer change if I allow the file to be read/write?
To be clear, dosomething
could be something like np.array()
or for i in f.readlines()
It's a poor practice. It has nothing to do with the open mode (read, write, read+write, append, binary mode, text mode ...).
In CPython, "it almost always works" because file objects are automatically closed when they become garbage (unreachable), and CPython's reference counting usually collects (non-cyclic) garbage very soon after it becomes garbage.
But relying on that is indeed poor practice.
If, for example, dosomething(f)
runs for an hour before it returns, chances are excellent the file object will remain open the entire time.
Note: in some cases, dosomething(f)
may be coded to explicitly close the passed-in file object itself. In those cases, it's not poor practice ;-)
Later: a related thing I've often seen is this:
data = open(file_path).read()
In CPython, the unnamed file object is garbage-collected (and so also closed) immediately when the statement completes, thanks to CPython's reference-counting. People are then surprised when they move their code to a different Python implementation, and get OS "too many open files!" complaints. Heh - serves 'em right ;-)
Example:
open("Output.txt", "w").write("Welcome")
print open("Output.txt").read()
This prints
Welcome
in CPython, because the unnamed file object from the first statement is garbage-collected (and closed) immediately when the first statement ends.
But:
output = open("Output.txt", "w")
output.write("Welcome")
print open("Output.txt").read()
probably prints an empty line in CPython. In this case, the file object is bound to a name (output
), so is not garbage collected when the second statement completes (a smarter implementation could theoretically detect that output
is never used again, and garbage-collect right away, but CPython does not).
"Welcome" is probably still in the file's memory buffer, so is not yet written to disk. So the third statement probably finds an empty file, and prints nothing.
In other implementations of Python, both examples may well print empty lines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With