Reputation:
I have quite a large Python(3) script that I'm trying to optimize.
To my understanding when you use with open(..., ...) as x
you DON'T need to use .close()
at the end of the "with" block (it is automatically closed).
I also know that you SHOULD add .close()
(if you are not using with
) after you are done manipulating the file, like this:
f = open(..., ...)
f.write()
f.close()
In an attempt to shove 3 lines (above) into 1 line I tried to change this:
with open(location, mode) as packageFile:
packageFile.write()
Into this:
open(location, mode).write(content).close()
Unfortunately this did not work and I got this error:
Traceback (most recent call last):
File "test.py", line 20, in <module>
one.save("one.txt", sample)
File "/home/nwp/Desktop/Python/test/src/one.py", line 303, in save
open(location, mode).write(content).close()
AttributeError: 'int' object has no attribute 'close'
The same line works fine when I remove the .close()
like this:
open(location, mode).write(content)
Why didn't open(location, mode).write(content).close()
work and is it safe to omit the .close()
function?
Upvotes: 5
Views: 1119
Reputation:
is it safe to omit the .close() function?
In current versions of CPython the file will be closed at the end of the for loop because CPython uses reference counting as its primary garbage collection mechanism but that's an implementation detail, not a feature of the language.
Also directly quoting user2357112: if you ever run this code on a different Python implementation, or if CPython ever abandons reference counting, your write could be arbitrarily delayed or even lost completely.
Why didn't open(location, mode).write(content).close() work?
This is because I was trying to call the .close()
method on the return of open(location, mode).write(content)
.
Upvotes: 1
Reputation: 21
It looks to me like the goal is for one function to occur right after another, however that isn't what is happening here.
open(location, mode) returns a file: https://docs.python.org/2/library/functions.html#open
In the syntax of
open(location, mode).write(content)
this is actually equivalent to
file = open(location, mode)
file.write(content)
the open statement becomes a type file which has a function called write(). The reason .close() doesn't work is that the file.write() doesn't have a function called close(). What this is trying to do is file.function().function().
In any case trying to optimize your code by reducing lines will not speed up performance noticeably, the normal with statement should be just as fast. Unless you are trying to go code golfing which is a whole other subject.
Have a good day!
Upvotes: 1
Reputation: 3415
That's because the .
(dot) operator works from left to right. In a.b
, b
is a message(method call) passed to a
. Say
a.b.c...
reads
do b in a and return r1, then
do c in r1 and return r2, then
...
Now open
returns an object that responds to read
message, but read
returns a str
/bytes
that has no method close
.
Bdw, always use a context manager i.e with with
in such context. And I wonder what does this have to do with optimization, as you said you are doing this while optimizing a script.
Upvotes: 1
Reputation: 281624
I also know that you SHOULD add
.close()
after you are done manipulating the file
Not if you're using with
.
Why didn't
open(location, mode).write(content).close()
work
Because instead of trying to close the file, you're trying to close the return value of the write
method call, which is an integer. You can't close an integer.
is it safe to omit the
.close()
function?
No. If you ever run this code on a different Python implementation, or if CPython ever abandons reference counting, your write could be arbitrarily delayed or even lost completely.
If you really want to shove this into a single line, you can write a single-line with
statement:
with open(location, mode) as packageFile: packageFile.write(whatever)
This is discouraged, but much less discouraged than relying on the file object's finalizer to close the file for you.
Upvotes: 1