1. [4 marks] For each of the following code snippets, write the value that is stored by the variable on the last line after the code snippet has been run.
Marking scheme: 1 mark per answer
a. def times_three (x): return x * 3
n = 2
times_three(n) n
2
b. x = 2
y = 3
t = x
x = y
y = t
y
2
c. def are_equal (x, y): return x == y
x = 1
a = 3
y = 1
n = are_equal (a, y)
n
False
d. a = 2
b = 3
a = b
b = b + 1
a
3
2. [5 marks] When you’re designing a function that takes a user-defined type (i.e. a type that is defined by a data definition, not by Python), in which steps of the How to Design Functions recipe do you need to consult the data definition? For each step in which you do need to consult the data definition, which part(s) of the data definition are you consulting and why?
Marking scheme: 1 mark per row
Step
|
Do you need to consult the data definition?
(yes/no/it depends)
|
Which part(s) of the data definition are you
consulting?
|
Why do you need to consult this part (or these parts)?
|
signature
|
yes
|
type name and possibly the interpretation
|
type name: to ensure that you’re using the correct name
interpretation: to understand what information this data type
represents
|
purpose
|
it depends
|
interpretation
|
In many cases you won’t need to
consult the data definition, but may need to understand what
information the data type
represents when you write the purpose
|
examples
|
yes
|
data type definition and/or examples
|
data type definition: to see how to form. data examples
examples: to check if you can use existing data examples in your
function design and/or to see how to form data of this type
|
template
|
yes
|
template
|
to copy the template from the appropriate data definition
|
function body
|
no
|
|
it’s unlikely that you’ll need to
consult the data definition once
you’re working on the function
body because you’ll already have
examples and the template, but you may want to go back to any part of the data definition to double check that your understanding of the type is correct
|
3. [7 marks] Design a function that takes two strings and returns True if they have the same length.
Marking scheme:
2 marks for the correct signature (-1 per error)
1 mark for a clear and correct purpose
3 marks for tests (empty case, same length, different length)
1 mark for correctness
4. [18 marks] Your friend has decided to start tracking their expenses so that they can create a budget. Here are the first few rows of the .csv file that your friend has been using to track the expenses.
Expense
|
Category
|
Payment
|
Amount
|
coffee
|
food
|
cash
|
1.95
|
theatre tickets
|
entertainment
|
credit card
|
88.40
|
rent
|
bills
|
cheque
|
580
|
groceries
|
food
|
debit card
|
54.10
|
There are many, many different categories (including ones not shown above) and your friend is likely to continue to create more categories over time. Your friend only uses cash, credit card, cheque, or debit card to pay for things.
Design data definitions to represent all of the information as data in your program.
Marking scheme
Enum Data Definition (PaymentType)
• 1 mark for the correct data type definition
• 1 mark for the interpretation
• 1 mark for the note about examples
• 1 mark for the correct template
• 1 mark for the correct note about origin of template
Compound Data Definition (Expense)
• 1 mark for a meaningful name
• 1 mark for the correct data type definition
• 1 mark for the necessary fields
• 1 mark if the fields have the right type
• 1 mark for interpretation - must include units for amount
• 1 mark for at least one correct example
• 1 mark for the correct template
• 1 mark for the correct template rules
List Data Definition (List[Expense])
• 1 mark for the correct data type definition and interpretation
• 2 marks for at least two correct examples (one empty, one non-empty)
• 1 mark for the correct template
• 1 mark for the correct template rules
from enum import Enum
from typing import NamedTuple, List
PaymentType = Enum('PaymentType', ['ca', 'cc', 'ch', 'dc'])
# interp. a payment type that is either cash ('ca'), credit card ('cc'), cheque ('ch'),
# or debit card ('dc')
# examples are redundant for enumerations
# template based on one of (4 cases), atomic distinct (4 times)
def fn_for_payment_type(pt: PaymentType) -> ...:
if pt == PaymentType.ca:
return ...
elif pt == PaymentType.cc:
return ...
elif pt == PaymentType.ch:
return ...
elif pt == PaymentType.dc:
return ...
Expense = NamedTuple('Expense', [('name', str),
('cat', str),
('payment', PaymentType),
('amount', float)])
# interp. an expense with a name, category ('cat'), payment type, and amount in CAD
E1 = Expense('coffee', 'Food', PaymentType.ca, 1.95)
E2 = Expense('theatre tickets', 'Entertainment', PaymentType.cc, 88.40)
# template based on compound and the reference rule
def fn_for_expense(e: Expense) -> ...:
return ... (e.name,
e.cat,
fn_for_payment_type(e.payment),
e.amount)
# List[Expense]
# interp. a list of expenses
L0 = []
L1 = [E1, E2]
# template based on arbitrary-sized and the reference rule
def fn_for_loe(loe: List[Expense]) -> ...:
# description of the acc
acc = ... # type: ...
for e in loe:
acc = ... (acc, fn_for_expense(e))
return acc
5. [2 marks] We could write a correct program (i.e. a program that works as expected) that does not follow the helper rules. Why is it important to follow the helper rules when you design programs? Give one concrete reason and justify your answer.
6. [7 marks] You have snow reports from your favourite mountain in the following form.
Date
|
Temperature
|
Visibility
|
Freezing Altitude
|
Base Snow
|
New Snow
|
19-Apr-17
|
-2
|
21.2
|
1700
|
370
|
4
|
20-Apr-17
|
-3.2
|
4.7
|
1750
|
374
|
2
|
21-Apr-17
|
1.8
|
18.3
|
1750
|
376
|
8
|
22-Apr-17
|
0.3
|
9.0
|
1750
|
384
|
13
|
This information is available in csv format in the file snow_report.csv. Here are data definitions that can be used to represent the relevant parts of this information as data in your program. THE PROBLEM STATEMENT IS ON THE NEXT PAGE.
from typing import NamedTuple, List
from cs103 import *
import csv
SnowReport = NamedTuple ('SnowReport', [('temp', float),
('vis', float), # in range [0, ...)
('base', int), # in range [0, ...)
('new', int)]) # in range [0, ...)
# interp. an alpine snow report with its temperature ('temp') in degrees Celsius,
# visibility ('vis') in kilometres, snow base ('base') in cm, and amount of
# snow in the last 24 hours ('new') in cm
SR1 = SnowReport(-2.0, 21.2, 370, 4)
SR2 = SnowReport(-3.2, 4.7, 374, 2)
SR3 = SnowReport(1.8, 18.3, 376, 8)
# template based on compound
def fn_for_snow_report(sr: SnowReport) -> ...:
return ... (sr.temp,
sr.vis,
sr.base,
sr.new)
# List[SnowReport]
# interp. a list of snow reports
L1 = []
L2 = [SR1, SR2]
# template based on arbitrary-sized and the reference rule
def fn_for_losr(losr: List[SnowReport]) -> ...:
# description of the acc
acc = ... # type: ...
for sr in losr:
acc = ... (acc, fn_for_snow_report(sr))
return acc
Continuing Problem 6: Design a read function to read this information from a file and store it as data in your program. We have provided the read template and suggest that you neatly edit it rather than re-writing your read function. Assume that the information is in a file named “snow_report.csv”. If you need to create
another information file, you can draw a table that shows the information (as above) and label it with the filename.
@typecheck
def read(filename: str) -> List[SnowReport]:
"""
reads information from the specified file and returns a list of snow reports
"""
# losr contains the result so far
losr = [] # type: List[SnowReport]
with open(filename) as csvfile:
reader = csv.reader(csvfile)
next(reader) # skip header line
for row in reader:
sr = SnowReport(parse_float(row[1]), parse_float(row[2]), parse_int(row[4]),
parse_int(row[5]))
losr.append(sr)
return losr
start_testing()
expect(read('snow_report.csv'), [SR1, SR2, SR3])
# plus one more test (will vary depending on the extra table they created)
summary()
Marking scheme
• 1 mark for updating the return type
• 1 mark for correctly updating the purpose
• 1 mark for correctly updating the accumulator type
• 2 marks for correctly updating the line that creates the SnowReport (including calls to parse_*)
• 2 marks for at least two correct examples
7. [10 marks] Design a function that takes a list of snow reports and returns the average snow base. (You must use the data definitions from Problem 6.)
Marking scheme
2 marks for the correct signature
1 mark for a clear and concise purpose
1 mark if the function consistently deals with the empty case in a reasonable way
1 mark for correct accumulator types (must both be correct)
1 mark for correct accumlator descriptions (must both be reasonable)
1 mark for the template being based on List[SnowReport]
2 marks for at least two correct examples
1 mark for correctness
8. [12 marks] Design a function that takes a list of snow reports and plots a line chart of the snow base over time.
You can assume that the reports are in the order in which they should be plotted. You can assume that the
function get_range, as described below by its signature and purpose, is fully implemented and works correctly. (Again, you must use the data definitions from Problem 6.)
def get_range (n: int) -> List[int]:
"""
returns a list of the first n integers
"""
Marking scheme
Helper function
2 marks for the correct signature
1 mark for a clear and concise purpose
1 mark if the function is based on correct template
1 mark for having at least one correct example
1 mark for correctness
Plot function
2 marks for the correct signature
1 mark for a clear and concise purpose
1 mark for correctly setting the title, x-axis label, and y-axis label
1 mark for correctly calling both helpers
1 mark for the correct call to plot