Closing file handle with chained method - python

In the case of a chained method when opening a file, eg.:
indata = open(from_file).read()
Is it necessary (or possible) to close the file handle opened with the open() function?
If not, is it best practice to instead do:
infile = open(from_file)
indata = infile.read()
infile.close()

In the case of a chained method when opening a file
This is the pitfall of chained method to open files, so the suggested solution is to use the with clause. The lifetime of an object is within the with block and the fileObj is closed automatically
with open(from_file) as fin:
indata = fin.read()
Why it is wrong?
You are at the mercy of GC to close files
If exception happens, you may not know where the exception happened, while opening or while reading
The other code piece
infile = open(from_file)
indata = infile.read()
infile.close()
Has also its pitfall.
If an exception happens, the file may not be closed
The code might take a different route and the close statement may not be exceuted

Related

Is 'open' in for loop a safe method in python?

Will codes like this close the f.txt safely?
for line in open('f.txt', 'r'):
pass
It runs correctly, but I'm worrying that the opened file will not be closed safely.
Best practice is to use like below:
with open(filename,'r') as file_obj:
# Do stuff with file_obj here
This will make sure that your file gets closed once you come out of with block.
It is good practice to use the with keyword when dealing with file objects. The advantage is that the file is properly closed after its suite finishes, even if an exception is raised at some point.
with open(filename, 'r') as f:
read_data = f.read()
if you are not using with statement then you should call f.close().If you don’t explicitly close a file, Python’s garbage collector will eventually destroy the object and close the open file for you, but the file may stay open for a while

File close error, [AttributeError: 'int' object has no attribute 'close'] when reducing file write code to a single line

Going through Zed Shaw's book Exercise 17 [about copying one file to another] where he reduces his these two lines of code
in_file = open(from_file)
indata = in_file.read()
into one as :
indata = open(from_file).read()
there's also a piece of code where he writes
out_file = open(to_file, 'w')
out_file.write(indata)
So I was reducing this into one line same as above :
out_file = open(to_file, 'w').write(indata)
This seems to work fine but when I close the out_file there's an error as:
Traceback (most recent call last):
File "filesCopy.py", line 27, in <module>
out_file.close()
AttributeError: 'int' object has no attribute 'close'
I am unable to grasp what is going on and how close() is working here?
The two are not equivalent. If you write out_file = open(to_file, 'w').write(indata), you have implicitly written:
# equivalent to second code sample
temp = open(to_file, 'w')
out_file = temp.write(indata)
Now as we can see in the documentation of write():
f.write(string) writes the contents of string to the file, returning the number of characters written.
So it returns an integer. So in your second sample out_file is not a file handler, but an integer. Further in the code, you somewhere aim to close the out_file file handler with out_file.close(). But since out_file is no longer a file handler, it thus makes no sense to call close on this.
Nevertheless, by using a context, you do no longer need to perform a .close() yourself, so more elegantly is probably:
with open(to_file, 'w') as out_file:
out_file.write(indata)
The reduction in the book itself is allowed (well at least semantically, it is better to use context manager), since the author probably never closes the file handle explicitly.
Following is usually better approach, both for reading & writing:
with open("myfile.txt", "w") as f:
# do something with f
There is no need to close f with this code.
With code val = open(to_file, 'w').write(indata) "val" will be return value of write function, not open function.
The write method returns the number of characters written in your file which is an integer not a file object and therefore doesn't have a close method.
In [6]: a = open('test', 'w')
In [7]: t = a.write('ssss')
In [8]: t
Out[8]: 4
Also, calling the I/O methods directly on open() is recommended only if you don't want to have any further interaction with the file. Besides, the most proper way to deal with file objects is to use a with statement that closes the file automatically at the end of the block and there's no need to call the close() manually.
with open('filename', 'w') as f:
# do something
The read() function reads the file and then returns the file content, so when you assign indata to read() it's assigning the returned file content. The difference is that the write() function returns the number of characters written, therefore your outdata is now an int object.
Read more about it here: https://docs.python.org/3.6/tutorial/inputoutput.html
Therefore, you cannot combine the write() function into one line and expect to have a referenced file object to close after, and that's disastrous.
The preferred way is to use the with block. Refer to #Willem's answer for more details.
The author "Zed" has already clarified when you will read the page 64 from that book. Please read below:
When I try to make this script shorter, I get an error when I close the files at the end.
You probably did something like this, indata = open(from_file).read(), which means you don’t need to then do in_file.close() when you reach the end of the script. It should already be closed by Python once that one line runs.

Use of python close command (LPTHW ex 17 extra credit) [duplicate]

I am having a great time trying to figure out why there doesn't need to be a closing attribute for this few lines of code I wrote:
from sys import argv
from os.path import exists
script, from_file, to_file = argv
file_content = open(from_file).read()
new_file = open(to_file, 'w').write(file_content)
new_file.close()
file_content.close()
I read some things and other people's posts about this, but their scripts were a lot more complicated than what I'm currently learning, so I couldn't figure out why.
I am doing Learning Python the Hard Way and would appreciate any help.
file_content is a string variable, which contains contents of the file -- it has no relation to the file. The file descriptor you open with open(from_file) will be closed automatically: file sessions are closed after the file-objects exit the scope (in this case, immediately after .read()).
open(...) returns a reference to a file object, calling read on that reads the file returning a string object, calling write writes to it returning None, neither of which have a close attribute.
>>> help(open)
Help on built-in function open in module __builtin__:
open(...)
open(name[, mode[, buffering]]) -> file object
Open a file using the file() type, returns a file object. This is the
preferred way to open a file.
>>> a = open('a', 'w')
>>> help(a.read)
read(...)
read([size]) -> read at most size bytes, returned as a string.
If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.
>>> help(a.write)
Help on built-in function write:
write(...)
write(str) -> None. Write string str to file.
Note that due to buffering, flush() or close() may be needed before
the file on disk reflects the data written.
Theres a couple ways of remedying this:
>>> file = open(from_file)
>>> content = file.read()
>>> file.close()
or with python >= 2.5
>>> with open(from_file) as f:
... content = f.read()
The with will make sure the file is closed.
When you do file_content = open(from_file).read(), you set file_content to the contents of the file (as read by read). You can't close this string. You need to save the file object separately from its contents, something like:
theFile = open(from_file)
file_content = theFile.read()
# do whatever you need to do
theFile.close()
You have a similar problem with new_file. You should separate the open(to_file) call from the write.

Opening a file and reading content in one line?

While doing some Python tutorials, the author of the book asked for the following (opening a file and reading its content):
#we could do this in one line, how?
in_file = open(from_file)
indata = in_file.read()
How can I do this in one line?
You can get all the contents of the file from a file handler by by simply extending what you have with your path and reading from it.
indata = open(from_file).read()
However, it's more obvious what's happening and easier to extend if you use a with block.
with open(from_file) as fh: # start a file handler that will close itself!
indata = fh.read() # get all of the contents of in_file in one go as a string
Beyond that, you should protect your file opening and closing from IOErrors if (for example) your file path does not exist.
Finally, files are by default opened read-only and raise an error if you (or someone else later) attempts to write to it, which will safeguard data blocks. You can change this from 'r' to a variety of other options depending on your needs.
Here is a fairly complete example with the above concepts.
def get_file_contents(input_path):
try:
with open(input_path, 'r') as fh:
return fh.read().strip()
except IOError:
return None

Closing a file in python opened with a shortcut

I am just beginning with python with lpthw and had a specific question for closing a file.
I can open a file with:
input = open(from_file)
indata = input.read()
#Do something
indata.close()
However, if I try to simplify the code into a single line:
indata = open(from_file).read()
How do I close the file I opened, or is it already automatically closed?
Thanks in advance for the help!
You simply have to use more than one line; however, a more pythonic way to do it would be:
with open(path_to_file, 'r') as f:
contents = f.read()
Note that with what you are doing before, you could miss closing the file if an exception was thrown. The 'with' statement here will cause it be closed even if an exception is propagated out of the 'with' block.
Files are automatically closed when the relevant variable is no longer referenced. It is taken care of by Python garbage collection.
In this case, the call to open() creates a File object, of which the read() method is run. After the method is executed, no reference to it exists and it is closed (at least by the end of script execution).
Although this works, it is not good practice. It is always better to explicitly close a file, or (even better) to follow the with suggestion of the other answer.

Categories