Exercise 3.1 - Solution

(a) Organizing a program as a collection of functions

# report.py
import csv

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    portfolio = []
    f = open(filename)
    f_csv = csv.reader(f)
    headers = next(f_csv)

    for row in f_csv:
        record = dict(zip(headers, row))
        stock = {
            'name' : record['name'],
            'shares' : int(record['shares']),
            'price' : float(record['price'])
        }
        portfolio.append(stock)
    f.close()
    return portfolio

def read_prices(filename):
    '''
    Read a CSV file of price data into a dict mapping names to prices.
    '''
    prices = {}
    f = open(filename)
    f_csv = csv.reader(f)
    for row in f_csv:
        try:
            prices[row[0]] = float(row[1])
        except IndexError:
            pass
    f.close()
    return prices

def make_report(portfolio,prices):
    '''
    Make a list of (name, shares, price, change) tuples given a portfolio list
    and prices dictionary.
    '''
    rows = []
    for stock in portfolio:
        current_price = prices[stock['name']]
        change        = current_price - stock['price']
        summary       = (stock['name'], stock['shares'], current_price, change)
        rows.append(summary)
    return rows

# ---- ADDED
def print_report(reportdata):
    '''
    Print a nicely formated table from a list of (name, shares, price, change) tuples.
    '''
    headers = ('Name','Shares','Price','Change')
    print ('%10s ' * len(headers)) % headers
    print ('-'*10 + ' ')*len(headers)
    for row in reportdata:
        print '%10s %10d %10.2f %10.2f' % row

# ---- END

# Read data files
portfolio = read_portfolio('Data/portfolio.csv')
prices    = read_prices('Data/prices.csv')

# Create the report data
report    = make_report(portfolio,prices)

# ---- ADDED
# Print it out
print_report(report)
# ---- END

(b) Creating a function for program execution

# report.py
import csv

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    portfolio = []
    f = open(filename)
    f_csv = csv.reader(f)
    headers = next(f_csv)

    for row in f_csv:
        record = dict(zip(headers, row))
        stock = {
            'name' : record['name'],
            'shares' : int(record['shares']),
            'price' : float(record['price'])
        }
        portfolio.append(stock)
    f.close()
    return portfolio

def read_prices(filename):
    '''
    Read a CSV file of price data into a dict mapping names to prices.
    '''
    prices = {}
    f = open(filename)
    f_csv = csv.reader(f)
    for row in f_csv:
        try:
            prices[row[0]] = float(row[1])
        except IndexError:
            pass
    f.close()
    return prices

def make_report(portfolio,prices):
    '''
    Make a list of (name, shares, price, change) tuples given a portfolio list
    and prices dictionary.
    '''
    rows = []
    for stock in portfolio:
        current_price = prices[stock['name']]
        change        = current_price - stock['price']
        summary       = (stock['name'], stock['shares'], current_price, change)
        rows.append(summary)
    return rows

def print_report(reportdata):
    '''
    Print a nicely formated table from a list of (name, shares, price, change) tuples.
    '''
    headers = ('Name','Shares','Price','Change')
    print ('%10s ' * len(headers)) % headers
    print ('-'*10 + ' ')*len(headers)
    for row in reportdata:
        print '%10s %10d %10.2f %10.2f' % row

# ---- ADDED
def portfolio_report(portfoliofile,pricefile):
    '''
    Make a stock report given portfolio and price data files.
    '''
    # Read data files
    portfolio = read_portfolio(portfoliofile)
    prices    = read_prices(pricefile)

    # Create the report data
    report    = make_report(portfolio,prices)

    # Print it out
    print_report(report)

portfolio_report('Data/portfolio.csv',
                 'Data/prices.csv')
# ---- END
Discussion

In this example, the entire report program has been packaged into a single function. One reason for doing this is that it packages the program up into a form that can be used to builder larger, more complex programs. For example, if you wanted to expand the program to do more than just generate the report, you can use the portfolio_report() function just to make that one part.

[ Back ]