Comp 112

Lecture 11

Files and Exceptions

2017.11.14

Exceptions

What Could Possibly Go Wrong?

There are many things that can go wrong in a program:

unassigned_variable += 1           #  NameError: name 'unassigned_variable' is not defined
42 [3]                             #  TypeError: 'int' object is not subscriptable
answer = 42 / 0                    #  ZeroDivisionError: division by zero
number = int ('forty two')         #  ValueError: invalid literal for int()

Some errors could be avoided by static analysis, which is analyzing the structure of a program without running it.

But others depend on the program interacting with the outside world and can’t be predicted.

Proceeding with Caution

One way to avoid errors is to use many conditional statements and only try to do things that we know will succeed.

def is_int_string (text) :
    # a predicate for strings parseable as ints
    return str.isdigit (text) or (len (text) > 0 and text [0] == '-' and str.isdigit (text [1 : ]))
def cautious_interactive_division () :
    x_str = input ('please enter the numerator: ')
    y_str = input ('please enter the denominator: ')
    if is_int_string (x_str) and is_int_string (y_str) :
        # it's safe to parse ints from them
        x_int = int (x_str)
        y_int = int (y_str)
        if y_int != 0 :
            # it's safe to divide them
            result = x_int / y_int
            print (x_str + ' / ' + y_str + ' = ' + str (result))
        else :
            print ("you can't divide by zero")
    else :
        print ('in order to divide you must enter two numbers')

Ploughing Ahead

But sometimes it’s easier to ask forgiveness than permission.

def brash_interactive_division () :
    x_str = input ('please enter the numerator: ')
    y_str = input ('please enter the denominator: ')
    try :
        x_int = int (x_str)        # may raise a ValueError
        y_int = int (y_str)        # may raise a ValueError
        result = x_int / y_int     # may raise a ZeroDivisionError
        print (x_str + ' / ' + y_str + ' = ' + str (result))
    except ZeroDivisionError :
        print ("you can't divide by zero")
    except ValueError :
        print ('in order to divide you must enter two numbers')

This style can make programs more clear and concise by focusing on the main execution path.

Try Statements

Raising Exceptions

Files

Files and Paths

There are two different ways of specifying a path:

Files and Paths in Python

Opening Files

To open a file in Python, use the “open” function:

open (<path> , <mode>)

The open function takes two arguments:

The modes we care about for now are:

If a call to open is successful then it will return a filehandle object.

This is a token representing your right to read from or write to the file.

File Handling Exceptions

File Input

File Output

def copy_shouty (in_path , out_path) :
    try :
        in_file = open (in_path , 'r')    # possible FileNotFoundError , IsADirectoryError
        out_file = open (out_path , 'x')  # possible FileExistsError
        for line in in_file :
            out_file.write (line.upper ())
        in_file.close ()
        out_file.close ()
    except FileExistsError :
        print ('the file ' + out_path + ' already exists.')
    except FileNotFoundError :
        print ('the file ' + in_path + ' does not exist.')
    except IsADirectoryError :
        print (in_path + ' is a directory, not a file.')

The Read-Modify-Write Pattern

A common pattern of working with files is to:

def alphabetize (in_path , out_path) :
    # alphabetizes the contents of a file containing one word per line
    words = [] # signature: list (str)
    try :
        # read:
        in_file = open (in_path , 'r')      # possible FileNotFoundError , IsADirectoryError
        for line in in_file :
            words.append (line)
        in_file.close ()
        # modify:
        words.sort()
        # write:
        out_file = open (out_path , 'x')    # possible FileExistsError
        for word in words :
            out_file.write (word)
        out_file.close ()
    except FileNotFoundError :
        print ('the file ' + in_path + ' does not exist.')
    except IsADirectoryError :
        print (in_path + ' is a directory, not a file.')
    except FileExistsError :
        print ('the file ' + out_path + ' already exists.')

To Do This Week: