Winter 2025
Midterm Test—Sample Solutions
CSC 148 H1S Version A
Question 1. OOP [8 marks]
Carefully read the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class MotorTransport :
" " "A r e p r e s e n t a t i o n of a motorized land v e h i c l e . " " "
make : s t r
_max_speed : i n t
def _ _ i n i t _ _ ( s e l f , make : s t r , max_speed : i n t ) −> None :
" " " I n i t i a l i z e t h i s MotorTransport . " " "
s e l f . make = make
s e l f . _max_speed = max_speed
class PassengerBus ( MotorTransport ) :
" " " A r e p r e s e n t a t i o n o f a p a s s e n g e r bus . " " "
d o u b l e _ d e c k e r : bool
repair_log : l i s t [ str ]
def _ _ i n i t _ _ ( s e l f , make : s t r , max_speed : i n t , d o u b l e _ d e c k e r : bool ) −> None :
" " " " I n i t i a l i z e this PassengerBus . " " "
M o t o r T r a n s p o r t . _ _ i n i t _ _ ( s e l f , make , max_speed )
s e l f . double_decker = double_decker
self . repair_log = []
def r e c o r d _ r e p a i r ( s e l f , r e c e i p t : s t r ) −> None :
" " " Add < r e c e i p t > t o t h e r e p a i r l o g o f t h i s b u s . " " "
m i d d l e _ i d x = len ( s e l f . r e p a i r _ l o g ) / / 2
s e l f . r e p a i r _ l o g . i n s e r t ( middle_idx , r e c e i p t )
i f __name__ == ' __main__ ' :
b u s 0 = P a s s e n g e r B u s ( ' AE35 ' , 2 0 0 , True )
b u s 1 = P a s s e n g e r B u s ( ' AE35 ' , 2 0 0 , True )
b u s 2 = M o t o r T r a n s p o r t ( ' AE35 ' , 1 8 0 )
Part (a) [4 marks] For each statement below, circle whether it is True or False.
The output of bus0 == bus1 would be True.
True
or
False
The relationship between PassengerBus and MotorTransport is composition
True
or
False
The output of isinstance(bus0, MotorTransport) would be True.
True
or
False
MotorTransport is an abstract class.
True
or
False
page 1 of 13
Midterm Test—Sample Solutions
CSC 148 H1S Version A
Winter 2025
Part (b) [1 mark]
Consider how the runtime of record_repair changes as the size of self.repair_log increases. Which of the
plots below capture this relationship? NOTE: Assume that len(self.repair_log) is a constant time operation.
Circle all correct options:
Option A
Option B
Option C
Option D
Option E
Part (c) [3 marks]
i– [1 mark] Write a reasonable Representation Invariant (RI) for the MotorTransport class. State the RI as
Python code. You do not need to explain your answer.
Two example solutions: self._max_speed >= 0 or len(self.make) > 0
This question should be graded based on 2 criteria:
• 0.5 marks if the RI is not redundant (e.g., already enforced by type hints)
• 0.5 marks if violating the RI produces an invalid instance of the class. For debatably correct RIs (e.g.,
should the current speed of a vehicle never exceed its maximum speed?), leave a short comment but
judge in favour of the student.
Other grading notes:
• Deduct 0.5 marks if the RI is written in English instead of Python.
• Deduct 0.25 marks if the solution is missing self. in the RI
ii– [2 marks] Briefly describe a possible set of changes that would ensure that your RI from the previous
question is documented and enforced. You may use line numbers or class/method names as needed. You
can describe the changes using English, or Python code.
1. Declare the RI in the MotorTransport class docstring (add to class docstring on line 2)
2. Modify MotorTransport.__init__, either by adding a precondition to the method docstring (lines
7), or by adding code to check if the corresponding parameter has a valid value, and raise an exception/correct the value otherwise.
3. Modify PassengerBus.__init__, either by adding a precondition to the method docstring (lines
17), or by adding code to check if the corresponding parameter has a valid value, and raise an exception/correct the value otherwise.
This question should be graded based on 3 criteria:
• 1 marks for adding the RI to the MotorTransport docstring
• 0.5 marks for modifying MotorTransport.__init__
• 0.5 marks for modifying PassengerBus.__init__
NOTE: If the student’s RI is not one of the expected solutions, then modify the rubric so that the 1 point
for modifying the initializers is instead awarded if they have modified the relevant methods (if any) such
that the RI is enforced.
Other grading notes:
page 2 of 13
Winter 2025
Midterm Test—Sample Solutions
CSC 148 H1S Version A
• If the solution changes the parent class’ initializer to change the value to a reasonable default, then
changes to the child’s initializer are not needed. (precondition or exception raising on the other hand
should be documented in the child’s initializer)
• Deduct 0.25 marks if the solution uses @check_contracts for enforcement but doesn’t change the
docstring
page 3 of 13
CSC 148 H1S Version A
Midterm Test—Sample Solutions
Winter 2025
Question 2. Polymorphism [6 marks]
Birds, cats, and lions are animals. A lion is a cat. Consider the following Python code:
def animal_sounds(animals) -> None:
for animal in animals:
try:
print(animal.speak())
except NotImplementedError:
print('not implemented!')
if __name__ == '__main__':
animal_sounds([Cat(), Bird(), Lion(), Animal()])
When the code is run, the output should be:
Meow!
Tweet!
Meow! Roar!
not implemented!
Part (a) [5 marks] Complete the classes below so that the code produces the expected output. You may NOT
define any instance attributes for the classes, and your answer must NOT contain any unnecessary duplicate code.
One of your classes MUST be abstract. You do not need to include any docstrings, but you must include return
type annotations where appropriate.
solution:
class Animal:
def speak(self) -> str:
raise NotImplementedError
class Cat(Animal):
def speak(self) -> str:
return "Meow!"
class Bird(Animal):
def speak(self) -> str:
return "Tweet!"
class Lion(Cat):
def speak(self) -> str:
# return super().speak() + " Roar!"
return Cat.speak(self) + " Roar!"
# alternative using super()
Marking Notes:
2 marks (0.5 each) for class name including parent class indicated
1.5 marks (0.5 each) for speak returning the right string
0.5 marks for Animal.speak raising NotImplementedError
0.5 marks for -> str type annotation being present
0.5 marks for use of super call for extending behaviour in Lion
Common Mistakes:
Did not make use of super call (or Parent's class name) to extend behaviour.
Did not have the right return type annotation based on implementation.
Defined unnecessary instance attributes.
When using parent class method, didn't pass self as an argument.
page 4 of 13
Winter 2025
Midterm Test—Sample Solutions
CSC 148 H1S Version A
Part (b) [1 mark] Our animal_sounds function is missing the type annotation for the parameter animals.
What is the most suitable type annotation for animals?
Answer: list[Animal]
page 5 of 13
CSC 148 H1S Version A
Midterm Test—Sample Solutions
Winter 2025
Question 3. Memory Models [8 marks]
Suppose we have the following code:
class _Node:
class LinkedList:
def __init__(self, item: Any) -> None:
# other methods not shown for space
self.item = item
self.next = None
def add(self, item: Any) -> None:
# STOP HERE!
new_node = _Node(item)
new_node.next = self._first
if __name__ == '__main__':
self._first = new_node
lst = LinkedList()
# START HERE!
lst.add(5)
In the memory model diagram below, we have already finished executing the line lst = LinkedList(). Update
the memory model diagram below to show the state of the program immediately before _Node.__init__ returns
in the call to lst.add(5) (i.e. start tracing the code at the comment # START HERE! and stop tracing at the
comment # STOP HERE!.)
_Node.__init__
id2
self
id1
item
id2
int
5
id3
NoneType
None
id1
_Node
item
id2
next
id3
LinkedList.add
id4
self
LinkedList
id4
_first
item
id3
id2
__main__
lst
id4
Marking Notes:
Note that the question clearly indicates where to stop tracing the code.
page 6 of 13
Winter 2025
Midterm Test—Sample Solutions
CSC 148 H1S Version A
Comment
Deduction
Entire middle stack frame is incorrect (stack frame name, variables, and values)
-3.5
Entire top stack frame is incorrect (stack frame name, variables, and values)
-2.5
Incorrect attribute name
-0.5
Incorrect stack frame name
-0.5
Incorrect value
-0.5
Incorrect variable name
-0.5
_Node is completely incorrect
-3.0
_Node is incorrect, aside from either type or memory address
-2.5
Stack frames are in the wrong order
-1.0
Unfilled blank
-0.5
Extra information was added to the memory model diagram (e.g., additional variables,
-1.0
attributes, stack frames, or crossing off stack frames)
page 7 of 13
CSC 148 H1S Version A
Midterm Test—Sample Solutions
Winter 2025
Question 4. ADTs [8 marks]
Part (a) [4 marks] Implement the MyStack methods push, pop, and is_empty according to their docstrings.
• You may assume that the LinkedList class has the following methods implemented:
pop, insert, __len__, and is_empty. See the aid sheet for their interfaces.
• You may not define any other methods, functions, or attributes.
• You may not use any builtin Python lists, sets, tuples, or dictionaries.
class MyStack:
"""The Stack ADT implemented using a LinkedList.
Private Attributes:
- _list: The LAST node of the LinkedList represents the TOP of the stack.
"""
_list: LinkedList
def __init__(self) -> None:
"""Initialize <self> to represent an empty stack."""
self._list = LinkedList()
def push(self, item: Any) -> None:
"""Push an item onto the stack."""
self._list.insert(len(self._list), item)
def pop(self) -> Any:
"""Pop an item off the stack and return it.
Precondition:
- not self.is_empty()
""
return self._list.pop(len(self._list) - 1)
def is_empty(self) -> bool:
"""Return True if the stack is empty, False otherwise."""
return self._list.is_empty()
Marking Notes:
0.5 marks for proper use of self
0.5 marks for proper syntax of calling self._list methods
1 mark for is_empty
1 mark for push (0.5 for using insert and 0.5 for correct index)
1 mark for pop (0.5 for using pop and 0.5 for correct index)
Common Deductions:
page 8 of 13
Winter 2025
Midterm Test—Sample Solutions
CSC 148 H1S Version A
Comment
Improper syntax for method call
Incorrect index used
insert should have been called
Method is (mostly) implemented correctly but does not make efficient use of the provided
LinkedList methods
Method was not implemented correctly and did not make use of the LinkedList methods
provided
Missing return
(One time deduction) did not use self._list
(One time deduction) Missing or incorrect use of self
Deduction
-0.5
-0.5
-0.5
-0.5
-1.0
-0.5
-0.5
-0.5
Part (b) [2 marks] In Big-O notation, what is the runtime of the push and pop methods you implemented in
the MyStack class? Your answer should be in terms of the number of items (𝑛) on the stack.
push: O(n) pop: O(n)
Part (c) [2 marks] In Big-O notation, what is the runtime of push and pop when using a Python list as the
underlying data structure, where the top of the stack is at the end of the list? Your answer should be in terms of the
number of items (𝑛) on the stack.
push: O(1) pop: O(1)
Marking Notes:
1 mark per answer
-1 deduction if improper use of Big-Oh (applied once)
(i.e., any factors other than 1 or n included, like n/2 or 5)
(note: it is fine here to write 1 rather than O(1)
or n rather than O(n))
page 9 of 13
Midterm Test—Sample Solutions
CSC 148 H1S Version A
Winter 2025
Question 5. Code Coverage [6 marks]
Consider the following function:
def i s _ p r i m e ( n : i n t ) −> bool :
" " " R e t u r n w h e t h e r <n > i s a p r i m e number . " " "
1
2
3
4
5
6
7
8
i f n <= 1 :
return F a l s e
i f n == 2 :
return True
f o r i in range ( 2 , n / / 2 + 1 ) :
i f n % i == 0 :
return F a l s e
return True
When choosing values of n to test, you may find this list of all prime numbers less than 32 to be useful:
2
3
5
7
11
13
17
19
23
29
31
Part (a) [2 marks] Write a pytest for this function that will result in line 7 executing. Include a short docstring
description and appropriate type annotations for your pytest.
Solution:
def test_is_prime_large_even() -> None:
"""Test is_prime on an even number, larger than 2.
"""
assert not is_prime(6)
Marking Notes (Common Deductions):
-0.5 docstring description and/or test name is unclear
or overly vague — be specific
-0.5 unclear test description;
should clarify that it is also > 1.
-0.5 return type annotation should be None
-0.5 should not take any parameters
-0.5 syntax error or improper use of assert
-1 line 7 not covered
Part (b) [4 marks] What is the minimum number of times we need to call this function in order to achieve 100%
code coverage? As part of your answer, fill in the table below with a minimal set of inputs to achieve 100% code
coverage. You may not need to use all rows in the table. We have completed the first row for you.
n
Which line numbers are executed
1
1, 2
2
1, 3, 4
Minimum number of test cases: 4
4 (a non-prime > 2) 1, 3, 5, 6, 7
13 (a prime > 2)
1, 3, 5, 6, 8
Marking Notes (Common Deductions):
-2 for not correctly stating that we need 4 cases (one per return!)
-0.5 for not correctly identifying which return is executed
for a specific test case.
-1 for completely missing a case in the table
page 10 of 13
Winter 2025
Midterm Test—Sample Solutions
CSC 148 H1S Version A
Question 6. Linked Lists I [6 marks]
Suppose we are in a LinkedList method and have variables prev and curr defined as shown in each diagram.
For each snippet of Python code below, update the diagram beside it to show how the LinkedList will look after
the code is executed. Clearly indicate what changes you have made.
In the space below each code snippet, write the output. If the code produces an error, write ERROR. If the code
results in an infinite loop, write INFINITE LOOP.
Part (a) [2 marks]
_first
p r e v . next = c u r r . next . next
p r e v . next . next = c u r r . next
print ( s e l f )
•
108
148
prev
curr
108
207
prev
curr
108
148
prev
curr
165
207
OUTPUT: INFINITE LOOP
Part (b) [2 marks]
_first
c u r r . item = 207
c u r r . next . next = None
print ( s e l f )
•
165
•
207
165
•
207
OUTPUT: [108 -> 207 -> 165]
Part (c) [2 marks]
_first
c u r r . next . next . next = c u r r . next
p r e v . next = c u r r . next
p r e v . next . next = None
print ( s e l f )
•
OUTPUT: [108 -> 165]
Marking Notes:
For each of the three parts:
1 mark for correct output
(if diagram was incorrect, some credit may still
be given for the output if it matches the diagram)
-0.5 for incorrect print formatting
(see LinkedList.__str__ on aid sheet)
1 mark for correct diagram
-0.5 per mistake
page 11 of 13
•
CSC 148 H1S Version A
Midterm Test—Sample Solutions
Winter 2025
Question 7. Linked Lists II [6 marks]
Complete the following LinkedList method according to its docstring description, and add an appropriate doctest
example to the docstring.
• You may not use any builtin Python lists, sets, tuples, or dictionaries.
• You may not use any other LinkedList methods.
def third_last_item(self) -> Any | None:
"""Return the value of the third last item in this linked list.
Return None if this linked list has fewer than 3 items.
# Write your doctest example here!
>>> ll = LinkedList([1, 2])
>>> ll.third_last_item() is None
True
# check if we have fewer than three items
if not self._first or not self._first.next or not self._first.next.next:
return None
# we have at least 3 items now!
# do something to keep track of third-last node
prev_prev = self._first # could use None instead
prev = self._first.next # could use None instead
curr = self._first.next.next # could use self._first instead
# Traverse the list until curr is the last node,
# so prev_prev is the third last node!
while curr.next is not None:
prev_prev = prev
prev = curr
curr = curr.next
return prev_prev.item
# alternative for the loop part using "look ahead":
curr = self._first
while curr.next.next.next is not None:
curr = curr.next
return curr.item
# alternatively, could first get the length of the list
# using a while cur is not None loop,
# then calculate the index we are looking for,
# and then do another standard while cur is not None loop
# to find the item with the target index.
Marking Notes:
2 marks for doctest (some common deductions below):
-0.5 for doctest syntax issue (e.g., missing >>>)
-0.5 incorrectly calling the method as if it were a function
page 12 of 13
Winter 2025
Midterm Test—Sample Solutions
-1 for incorrect test case
-2 no doctest
4 marks for the method body (some common deductions below):
-4 if relies on prohibited methods / no evidence
of understanding of how to work with LinkedLists
-1 if used prohibited methods in a minor way
-1 for any logical error in the implementation
-1 for returning a node instead of its item
-1 for not handling edge case properly
-0.5 marks for a syntax error
page 13 of 13
CSC 148 H1S Version A
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )