Exercise 2.3 - Solution
(b) Collecting Data
# 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:
stock = {
'name' : row[0],
'shares' : int(row[1]),
'price' : float(row[2])
}
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
# ---- ADDED CODE
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
# ---- END
# Read data files and create the report data
portfolio = read_portfolio('Data/portfolio.csv')
prices = read_prices('Data/prices.csv')
# ---- ADDED
# Generate the report data
report = make_report(portfolio, prices)
for row in report:
print row
# ---- END
(c) Making a formatted table
# report.py
...
# Read data files and create the report data
portfolio = read_portfolio('Data/portfolio.csv')
prices = read_prices('Data/prices.csv')
# Generate the report data
report = make_report(portfolio, prices)
# ---- CHANGED
# Print a table
for row in report:
print '%10s %10d %10.2f %10.2f' % row
# ---- END
(d) Adding some headers
Here are different ways to output headers:
headers = ('Name','Shares','Price','Change')
# Solution 1: An obvious, but hard-coded approach
print '%10s %10s %10s %10s' % headers
print '---------- ---------- ---------- ----------'
# Solution 2: An algorithmic approach
for h in headers:
print '%10s' % h, # Note: , omits the newline
print
print ('-'*10 + ' ')*len(headers)
# Solution 3: Use the string replication operator
# This next line takes a format string like '%10s' and replicates it into
# a format string like '%10s %10s %10s ...'. We then format that against a
# tuple of the headers
print ('%10s '*len(headers)) % headers
print ('-'*10 + ' ')*len(headers)
Complete Solution
# 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:
stock = {
'name' : row[0],
'shares' : int(row[1]),
'price' : float(row[2])
}
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
# Read data files and create the report data
portfolio = read_portfolio('Data/portfolio.csv')
prices = read_prices('Data/prices.csv')
# Generate the report data
report = make_report(portfolio, prices)
# Output the report
headers = ('Name', 'Shares', 'Price', 'Change')
print '%10s %10s %10s %10s' % headers
print ('-' * 10 + ' ') * len(headers)
for row in report:
print '%10s %10d %10.2f %10.2f' % row
[ Back ]