Exercise 1.7

Objectives:

  • How to define a simple function.

  • Using a function to perform repeated calculations.

  • Ignoring bad input data by catching and ignoring exceptions.

  • Using a library module.

Files Created: None.

Files Modified: pcost.py

(a) Defining a function

You can define a simple function using the def statement. For example, try this:

>>> def greeting(name):
       'Issues a greeting'
       print 'Hello', name

>>> greeting('Guido')
Hello Guido
>>> greeting('Paula')
Hello Paula
>>>

If you want to return a result, use the return statement. For example:

>>> def square(x):
        'Squares x'
        return x * x

>>> r = square(4)
>>> r
16
>>>

If the first statement of a function is a string, it serves as documentation. Try typing a command such as help(greeting) to see it displayed.

(b) Turning a script into a function

Take the code you wrote for the pcost.py program in the last exercise and turn it into a function portfolio_cost(filename) that takes a filename as input, reads the portfolio data in that file, and returns the total cost of the portfolio.

Note

If you create a .py file that only contains a function definition, the interpreter has to run that file in order for the function to be available for you to use. If you’re in IDLE, simply run the file that contains the function definition. If you working on the Unix command line, run python using the -i option such as this:

% python -i pcost.py
>>>

Alternatively, if you’re already working in the interpreter, you can run the contents of a file using execfile() like this:

>>> execfile('pcost.py')
>>>

Try your new function by running your code (using one of the above techniques) and then trying it out at the interactive Python prompt:

>>> portfolio_cost('Data/portfolio.csv')
44671.15
>>>

What happens if you try your function on a file with some missing fields?

>>> portfolio_cost('Data/missing.csv')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pcost.py", line 11, in portfolio_cost
    nshares    = int(fields[1])
ValueError: invalid literal for int() with base 10: ''
>>>

At this point, you’re faced with a decision. To make the program work you can either sanitize the original input file by eliminating bad lines or you can modify your code to handle the bad lines in some manner. Let’s take the latter option.

(c) Adding some error handling

Modify your function slightly so that it is able to recover from lines with bad data. For example, the conversion functions int() and float() raise a ValueError exception if they can’t convert the input. Use try and except to catch and print a warning message about lines that can’t be parsed.

Try reading the Data/missing.csv file again:

>>> portfolio_cost('Data/missing.csv')
Bad line: '"MSFT",,51.23\n'
Bad line: '"IBM",,70.44\n'
27381.15
>>>

(d) Using a library function

Python comes with a large standard library of useful functions. One library that might be of use here is the csv module. You should use it whenever you have to work with CSV data files. Here is an example of how it works:

>>> import csv
>>> f = open('Data/portfolio.csv')
>>> f_csv = csv.reader(f)
>>> headers = next(f_csv)
>>> headers
['name', 'shares', 'price']
>>> for row in f_csv:
        print row

['AA', '100', '32.20']
['IBM', '50', '91.10']
['CAT', '150', '83.44']
['MSFT', '200', '51.23']
['GE', '95', '40.37']
['MSFT', '50', '65.10']
['IBM', '100', '70.44']
>>>

One nice thing about the csv module is that it deals with a variety of low-level details such as quoting and proper comma splitting. In the above output, you’ll notice that it has stripped the double-quotes away from the names in the first column.

Modify your pcost.py program so that it uses the csv module for parsing and try running earlier examples.

Links