CPSC170 Lab 3

Exceptions

Placing Exception Handlers

The file parse_ints.py contains a program that does the following:

Save parse_ints.py to your directory and run it. If you give it the input:

10 20 30 40

It should print:

The sum of the integers on the line is 100.

Now try a line that contains both integers and other values, for example:

We have 2 dogs and 1 cat.

You will get a ValueError when it tries to call int() on "We", which is not an integer. One way around this is to put the loop that computes the sum inside a try block and handle the ValueError, by passing. This way if it's not an integer it doesn't cause an error; it goes to the exception handler, which does nothing. Do this as follows:

  1. Modify the program to add a try statement that encompasses the entire for loop. Handle a ValueError and have pass for the except body.

  2. Compile and run the program and enter a line with mixed integers and other values. You should find that it stops summing at the first non-integer, so the input "We have 2 dogs and 1 cat" will produce a sum of 0, and the line "1 fish 2 fish red fish blue fish" will produce a sum of 1. This is because the entire loop is inside the try, so when an exception is raised the loop is terminated.

  3. To make it continue, move the try and except clauses inside the loop. Now when an exception is thrown, the next statement is the next iteration of the loop, so the entire line is processed. Both the dogs-and-cats input and the fish input should now give a sum of 3.

Throwing Exceptions

The file factorials.py contains a program that calls the factorial function of the class to compute the factorials of integers entered by the user. Save the file to your directory, study the code, and run factorials.py to see how it works. Try to break the program, there are two different ways that you can, non-integer input, and negative input. You can use exceptions to handle both types of input errors. First, fix the non-integer input errors by doing the following:

  1. When a non integer input is entered the call to the built-in function int fails with a ValueError. Modify the loop body so that if a value error is produced, the factorial function will not be executed and the result will not be printed, but instead it should print "invalid input". In either case the program should still prompt the user for another factorial. Run the program and verify that it continues to run if an integer is not entered.

    Try entering a negative integer to the program. Note that the program does not crash, but it produces erroneous output, factorial does not exist for negative integers. The pre-condition for the compute_factorial function is that the input must be a positive integer. This means that it is the calling function's responsibility to not pass invalid input. However, by using exceptions, it is possible for a function to pass information back to the calling function about how its preconditions were not met. This make both finding and dealing with errors in code much easier.

  2. Fix the negative-integer input error by raising a ValueError in the compute_factorial function if the non_negative_integer parameter is negative. You do this by instantiating a ValueError object, and using the raise statement. Note, the value error should specify a string explaining why the exception was raised. Run the program and verify that inputting a negative integer does not stop the program.

Creating Exceptions

Putting checks on user input to prevent program crashes is often called idiot-proofing code. The factorial program from the previous exercise is now idiot-proof, but it could be more user friendly. For example, if the user enters invalid input it doesn't inform the user why the input was invalid. The compute_factorials function can easily distinguish between why an exception was raised if the exceptions are different. Currently, however, both exceptions, non-integer and negative integer exceptions, are ValueError exceptions. This can be fixed by using inheritance to create a new exception type, BadInputError, by doing the following:

  1. Inside the factorials.py file create a new class called BadInputError that extends Exception. Add the __init__ method to the class that takes a message that describes the error and stores it as an instance variable. Also add the __str__ method to the class that returns the message instance variable.

  2. In the compute_factorial function change the type of the raised exception to BadInputError. In the compute_factorials function add a second except clause for a BadInputError. The body of the BadInputError clause should print an error message explaining that the input must be non-negative. Also modify the print statement of the ValueError except clause to state that the input must be an integer. Run the program and verify that a different message is printed depending on the error in the input.

Submission

Submit a zip file of your code on the course Inquire site that uses your last names as the file name.