1

I am learning about exceptions and so performing some file operations and testing various parts of code that can possibly generate exceptions while working with files in Python. I am executing this Python 2.7 code on Canopy.

#!/usr/bin/python

import os

try:
    fp = open('testfile', 'r')
except IOError:
    print 'File not opened successfully'
else:
    print 'File opened successfully'
    try:
        fp.write('Hello!')
    except IOError:
        print 'Write not allowed on this file'
    else:
        print 'Write successful'
        try:
            fp.close()
        except IOError:
            print 'File not closed properly'
        else:
            print 'File closed successfully'
finally:
    if os.path.exists(fp.name):
        os.remove(fp.name)

When I execute this code, I get the following output:

File not opened properly

NameErrorTraceback (most recent call last)

/home/sr/Python/tcs.py in ()

--> 185 if os.path.exists(fp.name)

NameError: name 'fp' is not defined

But if I change the access mode of file to 'w', Then everything seems to work properly with the correct output as:

File opened successfully

Write successful

File closed successfully

I cannot understand why the 'r' mode is not making the file open properly and thus the fp file object is not created. Please help me figure the problem out.

P.S.: Also I would like to know if there is a better way of implementing the same thing. But this is optional.

Community
  • 1
  • 1
Rahul
  • 143
  • 1
  • 17

1 Answers1

0

Explanation

The error combined with your printout should be pretty self-explanatory: the variable fp does not exist if you can't open the file.

The mode 'r' indicates that you want to open the file for reading. You can not read something that is not there, so you end up going to the finally block in your code after processing the IOError. But the error occurs before fp was set, so there is no variable fp, hence the error. [Solutions below]

The mode 'w' indicates that you want to open for writing, but from scratch. There is also an 'a' mode to append if the file already exists. You can write to a non-existent file just fine, so your code does not fail. In fact, if the file did exist in 'w' mode, it would be trucated and any previous contents would be lost.

Try creating an empty file and running with mode 'r'. You should get an exception that prints 'Write not allowed on this file'. That is because, as your error message correctly indicates, writing to a file opened in read mode is not allowed.

Improvements

There are two major improvements that you can make to your code. One is fixing the logical flaws, the other is a major stylistic improvement using with statements.

You have two major logic errors. The first is in the outermost finally block that you already saw. The simplest fix is moving the contents of the finally block into the else, since you don't have any action to take if the file was not opened. Another solution is to refer to the file name you are trying to open in the first place. For example, you could store the file name into a variable and use that:

filename = 'testfile'
try:
    fp = open(filename, 'r')
...
finally:
    if os.path.exists(filename):
        os.remove(filename)

The second major logic error is that you do not close the file if your write fails. Notice that you call fp.close() only in the else clause of your try block. If should instead appear in a finally block. The print statement should of course stay in the else. Change

 else:
    print 'Write successful'
    try:
        fp.close()
    ...

to

 else:
    print 'Write successful'
 finally:
    try:
        fp.close()
    ...

The entire code can be improved stylistically by using with blocks to manage your file operations. The obvious way to do this is as follows:

fname = 'testfile'
with open(fname, 'r') as fp:
    fp.write('Hello!')
if os.path.exists(fname):
    os.remove(fname)

You will not get as many detailed messages when things fail, but overall, this code is cleaner, shorter and more robust than what you have. It guarantees that the file will be closed whether or not an exception occurred anywhere along the way. If you need the detailed error output that you currently have, keep using the current try blocks. The reason that most people will prefer with is that any error that occurs will have a detailed desciption and a line number that it happened on, so you basically get all the necessary information with a lot less work.

Here are some additional resources to help you understand with and context managers:

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Thanks a lot ! I now get that files that dont't exist are not created when we use the 'r' mode – Rahul Jul 20 '17 at 04:17
  • No problem at all. It's really nice to see beginners putting some real effort into asking proper questions. I wish you the best of luck in your continued endeavors. – Mad Physicist Jul 20 '17 at 05:11
  • Thank you so much. Wish you the best luck too :) – Rahul Jul 20 '17 at 05:15