Week 10: Exercises

1. Files

Write a program whose command-line arguments are filenames. The program should print the contents of all the files to standard output in the order in which they appear on the command line. If any file does not exist, print ' == MISSING: <filename> == ' in its place. Use an exception handler to handle missing files.

2. Exception Performance

How expensive are exceptions? To find out, perform the following experiment. Consider the following functions square1() and square2(). Both of them return the square of a value, but sqaure1() returns the square normally, while square2() throws it in an exception:

def square1(x):
    return x * x

class Answer(Exception):
    def __init__(self, x):
        self.x = x

def square2(x):
    raise Answer(x * x)

Write a program that adds the squares of the numbers from 1 to 10,000,000 in two ways, first by calling square1(), then by calling square2() and using a try...except block. Use the time.time() function to measure the total cost of adding these squares in each of these ways.

3. Stream Classes

Write a class Stream for reading lines of text, with subclasses StringStream and FileStream. Stream will be an abstract class: it does not make sense to create an instance of Stream, only of one of its subclasses.

On any Stream, it should be possible to call a method next_line() that reads the next input line and returns it as a string, or returns None at the end of the input. There should be a constructor StringStream(s) that takes a string containing data to read, and a constructor FileStream(name) that builds a FileStream that will read data from the given file. You will have separate implementations of next_line() in each of these subclasses.

The Stream class should also have a method next_non_empty() that reads lines until it finds a line that it non-empty, then returns it. If there are no more non-empty lines, the method should return None. You will need to implement this method only once.

4. Expression Interpreter

Write a program that reads and evaluates arithmetic expressions such as "22 + 31 - 4". In these expressions, the only supported arithmetic operators are "+" and "-", and parentheses are not allowed. Operators must be preceded and followed by writespace. Each time your program wants the user to enter an expression, it should print the prompt 'expr> ' and then wait for user input. The user can type 'exit' to exit the program. For example:

expr> 2 + 3
7
expr> 1 + 22 – 3
20
expr> exit

Your program should include a function eval() that takes a string containing an arithmetic expression and returns its value. If an expression is invalid (e.g. it contains a value that is not an integer, or includes an unsupported operator such as '*') then eval() should raise a InvalidExpression exception, which is a custom exception type that you should define. If an InvalidExpression exception is raised, then your program's top-level code should catch it, print an error message, then continue execution, prompting the user for the next expression. For example:

expr> 2 + 3
7
expr> 5 + b
Invalid expression
expr> 7 * 2
Invalid expression
expr> exit