1.1 — Variables, Data Types, and Expressions
Primitive types (int, float, str, bool); variable assignment; type conversion; operator precedence; basic expression evaluation
# Variable assignment and type conversion
name = "Ada"
age = 17
gpa = 3.85
is_senior = True
# Build a record string with explicit conversions
record = name + " (" + str(age) + "): " + str(gpa)
print(record) # Ada (17): 3.85
1.2 — Input, Output, and String Formatting
input(), print(), f-strings, escape sequences, integer vs. float input parsing
# Build an interactive area calculator
length = float(input("Length (m): "))
width = float(input("Width (m): "))
area = length * width
print(f"Area = {area:.2f} m²")
1.3 — Selection: if/elif/else and Boolean Logic
Comparison operators, logical and/or/not, truth tables, short-circuit evaluation, the dangling-else problem
# Letter-grade classifier (Ontario Achievement Chart)
def letter_grade(percent):
if percent >= 80: return "Level 4"
elif percent >= 70: return "Level 3"
elif percent >= 60: return "Level 2"
elif percent >= 50: return "Level 1"
else: return "R"
1.4 — Iteration: for, while, and Loop Tracing
Counted loops with range(), conditional loops, accumulator pattern, sentinel-controlled loops, off-by-one errors
# Sum of numbers 1..n using accumulator pattern
def sum_to(n):
total = 0
for i in range(1, n + 1):
total += i
return total
print(sum_to(100)) # 5050 (Gauss)
1.5 — Program Tracing and Desk Checks
Variable trace tables, dry runs, predicting output, the IPO (Input-Process-Output) chart
2.1 — 1-D Lists (Arrays): Indexing, Slicing, Mutation
List literal syntax, zero-based indexing, negative indices, slice notation, common methods (.append, .pop, .insert, .remove)
scores = [82, 76, 91, 68, 88]
print(scores[0]) # 82 (first)
print(scores[-1]) # 88 (last)
print(scores[1:4]) # [76, 91, 68]
scores.append(95) # mutate in place
avg = sum(scores) / len(scores)
2.2 — 2-D Lists / Multi-Dimensional Arrays
Lists of lists, row/column indexing, nested loops to traverse a grid, building a tic-tac-toe or seating chart
# 3 x 3 game board (None = empty)
board = [
[None, "X", None],
[None, "O", None],
["X", None, None]
]
for row in board:
for cell in row:
print(cell if cell else ".", end=" ")
print()
2.3 — Dictionaries (Maps) and Records
Key-value pairs, lookup vs. linear search, dictionaries as records, nested dictionaries
student = {
"name": "Hopper",
"id": 100451,
"grades": {"ICS4U": 94, "MCV4U": 88}
}
print(student["grades"]["ICS4U"]) # 94
2.4 — Strings as Sequences
Strings are immutable sequences; common methods (.split, .join, .strip, .lower, .replace, .find); slicing and reversal
2.5 — File I/O: Reading and Writing Text Files
open(), context managers (with statement), reading lines, writing CSV-like data
# Read a roster file, output the average mark
with open("roster.csv") as f:
total, count = 0, 0
for line in f:
name, mark = line.strip().split(",")
total += int(mark)
count += 1
print(f"Class average: {total/count:.1f}")
2.6 — Classes and Objects (Introduction to OOP)
Defining a class, attributes, methods, the __init__ constructor, encapsulation; objects vs. records
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def promote(self):
self.grade += 1
def __str__(self):
return f"{self.name} (Grade {self.grade})"
s = Student("Turing", 11)
s.promote()
print(s) # Turing (Grade 12)
3.1 — Defining and Calling Functions
Function definition, parameters vs. arguments, return values, docstrings, the DRY principle
def celsius_to_fahrenheit(c):
"""Convert °C to °F."""
return c * 9/5 + 32
def describe_temp(c):
f = celsius_to_fahrenheit(c)
return f"{c}°C = {f:.1f}°F"
3.2 — Parameters: Positional, Keyword, Default, and *args
Default arguments, named arguments, variable-length argument lists, pass-by-object-reference behavior
3.3 — Variable Scope and the LEGB Rule
Local, Enclosing, Global, Built-in scope; the global keyword; why mutable globals are dangerous
x = 10 # global
def outer():
x = 5 # enclosing (relative to inner)
def inner():
x = 1 # local
print(x) # 1
inner()
print(x) # 5
outer()
print(x) # 10
3.4 — Recursion: Base Cases and Recursive Cases
Designing the base case, the recursive call, the call stack, and the equivalence with iteration
def factorial(n):
if n <= 1: # base case
return 1
return n * factorial(n-1) # recursive case
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
3.5 — Top-Down Design and Stepwise Refinement
Decompose a problem into modules; structure charts; bottom-up integration; library reuse
4.1 — Linear Search and Binary Search
Sequential lookup vs. divide-and-conquer; precondition: binary search requires a sorted list; off-by-one issues with bounds
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1
while lo <= hi:
mid = (lo + hi) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1 # not found
4.2 — Bubble, Insertion, and Selection Sort
The three classical O(n²) sorts; correctness invariants; in-place vs. stable sort
def insertion_sort(a):
for i in range(1, len(a)):
key = a[i]
j = i - 1
while j >= 0 and a[j] > key:
a[j+1] = a[j]
j -= 1
a[j+1] = key
return a
4.3 — Merge Sort and Quicksort (Divide & Conquer)
Recursive sort algorithms; merge step; pivot selection; average vs. worst-case behavior
def merge_sort(a):
if len(a) <= 1:
return a
mid = len(a) // 2
left = merge_sort(a[:mid])
right = merge_sort(a[mid:])
# merge
out, i, j = [], 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
out.append(left[i]); i += 1
else:
out.append(right[j]); j += 1
out += left[i:] + right[j:]
return out
4.4 — Big-O Notation and Algorithm Efficiency
O(1), O(log n), O(n), O(n log n), O(n²), O(2ⁿ); growth rates; counting basic operations
4.5 — Algorithm Selection and Trade-offs
Choose the right algorithm: small lists, nearly-sorted data, memory constraints, stability requirements
5.1 — Testing & Debugging Strategies
Unit tests, boundary cases, regression testing, debugger basics, the rubber-duck method, common bug types (off-by-one, type, scope)
import unittest
def divide(a, b):
if b == 0:
raise ValueError("divide by zero")
return a / b
class TestDivide(unittest.TestCase):
def test_basic(self):
self.assertEqual(divide(10, 2), 5)
def test_zero(self):
self.assertRaises(ValueError, divide, 10, 0)
5.2 — Version Control with Git (Essentials)
Repos, commits, branches, merges, pull requests, .gitignore; why version control matters in collaborative software
5.3 — The Software Development Life Cycle & Maintainability
Requirements gathering, design, implement, test, deploy, maintain; commenting; naming conventions (PEP 8); code reviews
5.4 — Emerging Technologies: AI, Machine Learning, Quantum Computing
High-level overview of how supervised learning, neural networks, and large-language-models work; introduction to qubits and quantum advantage
5.5 — Ethical & Environmental Issues in Computing
Privacy, algorithmic bias, intellectual property, e-waste, energy footprint of data centres & AI training, ethical AI design
5.6 — History of Computing & Career Pathways
From Babbage and Lovelace to modern cloud computing; CS-related careers in Canada (software dev, data science, security, ML, robotics, game dev); Canadian post-secondary CS programs