First-year courses · Computing
Introduction to computer science with Python
Python types, control flow, functions, recursion, lists and dictionaries, Big O, binary search, sorting and testing: intro computer science flashcards.
About this deck
Most Canadian first-year computer science courses now teach programming in Python, and this deck follows that style. It covers values and types (integers, floats, strings, Booleans), mutability, conditionals and loops, functions, scope and default arguments, recursion and the call stack, lists, tuples, dictionaries and sets, list comprehensions, algorithm analysis with Big O notation, linear and binary search, selection, insertion and merge sort, and the basics of testing and debugging.
No programming experience is assumed, but you will get much more from the deck if you have Python 3 installed or open in a browser-based notebook so you can try the examples. The examples are written as small snippets; a line such as 7 // 2 gives 3 means that evaluating 7 // 2 in Python produces 3.
Programming knowledge sticks when you run code, so for every card with an example, predict the output before flipping and then type it into Python to confirm. If your prediction was wrong, write down why; those notes become your best exam review. For the Algorithms and complexity tag, practise explaining the running time of each algorithm in terms of how many times its loops repeat. Mix tags regularly, because exam questions often combine them, such as tracing a recursive function that builds a list.
Common mistakes: confusing print with return (a function that only prints gives back None); copying a list with b = a and being surprised when changes to b also change a; and off-by-one errors with range, which stops before its end value. In Big O questions, students often count only the outer loop and miss that a nested loop over the same data makes the work quadratic.
Before you start: No programming background required; comfort with high school algebra and functions helps.
All 43 cards
Cover the definitions with a sheet of paper and test yourself, or use the study modes above.
Data types and variables
- Variable (Python)
- A name that refers to a value (an object) in memory; assignment with = binds the name, and the same name can later refer to something else.Example: x = 5 then x = x + 1 leaves x referring to 6.
- int and float division
- / always gives a float; // gives floor division (rounding down); % gives the remainder, matching floor division.Example: 7 / 2 gives 3.5, 7 // 2 gives 3, 7 % 2 gives 1, and -7 // 2 gives -4.
- Floating-point rounding error
- Most decimal fractions cannot be stored exactly in binary, so float arithmetic can be slightly off; compare floats with a tolerance, not ==.Example: 0.1 + 0.2 gives 0.30000000000000004; use math.isclose(a, b) instead.
- String indexing and slicing
- Strings are sequences of characters indexed from 0; s[i] gets one character and s[a:b] gets characters from index a up to but not including b.Example: 'python'[0] is 'p'; 'python'[1:4] is 'yth'; 'python'[-1] is 'n'.
- Boolean operators and short-circuiting
- and, or and not combine True/False values; Python stops evaluating as soon as the result is known.Example: x != 0 and 10 / x > 1 never divides by zero, because the right side is skipped when x is 0.
- Type conversion
- Functions such as int(), float(), str() and bool() build a value of another type; int() of a float truncates toward zero.Example: int('42') gives 42; int(3.9) gives 3; str(3.0) gives '3.0'.
- Mutable versus immutable
- Mutable objects (lists, dicts, sets) can be changed in place; immutable ones (int, float, str, tuple) cannot, so operations create new objects.Example: s = 'cat'; s[0] = 'b' raises TypeError, but a list element can be reassigned.
Control flow
- Conditional statement
- if, elif and else choose which block runs based on Boolean conditions; only the first true branch executes.Example: if n > 0: sign = 1 elif n < 0: sign = -1 else: sign = 0.
- for loop and range
- A for loop runs its body once for each item of an iterable; range(start, stop, step) produces integers from start up to but not including stop.Example: list(range(2, 10, 3)) is [2, 5, 8].
- while loop
- Repeats its body as long as a condition stays true; something in the body must eventually make it false, or it becomes an infinite loop.Example: n = 10; while n > 1: n = n // 2 runs 3 times (10, 5, 2, then 1).
- break and continue
- break exits the nearest enclosing loop immediately; continue skips the rest of the current pass and moves to the next one.Example: for x in data: if x < 0: continue (negative values are skipped).
- Accumulator pattern
- Initialize a variable before a loop and update it on each pass to build a total, count, list or other result.Example: total = 0; for i in range(1, 101): total += i gives 5050.
- Off-by-one error
- A bug where a loop runs one time too many or too few, often from misreading range ends or using <= instead of <.Example: range(1, 10) stops at 9; to include 10 use range(1, 11).
Functions and recursion
- Function
- A named, reusable block of code defined with def; parameters are the names in the definition, arguments are the values passed in a call.Example: def area(w, h): return w * h, then area(3, 4) gives 12.
- return versus print
- return sends a value back to the caller and ends the function; print only displays text. A function with no return statement gives back None.Example: def f(): print(5) then y = f() prints 5 but y is None.
- Variable scope
- Names assigned inside a function are local to it; Python looks names up in Local, Enclosing, Global, then Built-in scope (LEGB).Example: Assigning x = 1 inside a function does not change a global x unless declared global.
- Default parameter values
- Parameters can have defaults used when no argument is given; defaults are evaluated once, so mutable defaults like [] are shared across calls.Example: def add(x, acc=[]): acc.append(x); return acc. Calling add(1) then add(2) returns [1, 2].
- Recursion
- A function that solves a problem by calling itself on a smaller version of the same problem until a simple case is reached.Example: def fact(n): return 1 if n == 0 else n * fact(n - 1); fact(5) gives 120.
- Base case
- The input for which a recursive function returns an answer directly without calling itself; without it, recursion never stops.Example: In the factorial function, n == 0 returning 1.
- Call stack
- The stack of active function calls, each with its own local variables; deep recursion fills it, and Python raises RecursionError (default limit about 1000).Example: fact(5) has six frames on the stack at its deepest point, fact(5) down to fact(0).
- Memoization
- Storing results of earlier calls so repeated subproblems are not recomputed; it turns naive recursive Fibonacci from exponential to linear time.Example: Decorating fib with functools.lru_cache makes fib(100) instant.
- Higher-order function
- A function that takes another function as an argument or returns one; lambda creates a small anonymous function.Example: sorted(['kiwi', 'fig', 'banana'], key=len) gives ['fig', 'kiwi', 'banana'].
Data structures
- List
- An ordered, mutable sequence that can hold items of any type; append adds to the end in amortized constant time.Example: nums = [3, 1]; nums.append(4) gives [3, 1, 4].
- Aliasing
- Two names referring to the same mutable object, so a change made through one name is visible through the other.Example: a = [1, 2]; b = a; b.append(3) leaves a as [1, 2, 3]. Use b = a.copy() for a separate list.
- Tuple
- An ordered, immutable sequence; useful for fixed groups of values and as dictionary keys.Example: point = (3, 4); x, y = point unpacks it.
- Dictionary
- A mutable mapping from unique, hashable keys to values, implemented as a hash table with average constant-time lookup, insert and delete.Example: counts = {}; for w in words: counts[w] = counts.get(w, 0) + 1.
- Set
- An unordered collection of unique, hashable items with fast membership tests and set operations (union, intersection).Example: set([1, 2, 2, 3]) is {1, 2, 3}; {1, 2} & {2, 3} is {2}.
- List comprehension
- A compact expression that builds a list from an iterable, optionally filtering: [expression for item in iterable if condition].Example: [x * x for x in range(5)] is [0, 1, 4, 9, 16].
- Nested list pitfall
- Multiplying a list that contains a list repeats references to the same inner list, so changing one row changes them all.Example: g = [[0] * 3] * 3; g[0][0] = 1 makes every row [1, 0, 0]. Use [[0] * 3 for _ in range(3)].
Algorithms and complexity
- Algorithm
- A finite, precise sequence of steps that solves a problem or computes a result for every valid input.Example: Long division and binary search are both examples.
- Big O notation
- Gives an upper bound on how an algorithm's running time (or memory) grows with input size n, ignoring constant factors and lower-order terms; it is most often quoted for the worst case.Example: 3n^2 + 5n + 2 steps is O(n^2).
- Common growth rates
- From fastest to slowest growth of work: O(1), O(log n), O(n), O(n log n), O(n^2), O(2^n).Example: For n = 1000: log2 n is about 10, n^2 is 1 000 000.
- Linear search
- Checking items one at a time until the target is found or the list ends; works on unsorted data and takes O(n) time.Example: Finding 7 in [4, 9, 7, 1] takes 3 comparisons.
- Binary search
- Searches a sorted sequence by comparing with the middle item and discarding half each step; O(log n) time.Example: 1 000 000 sorted items need at most 20 comparisons, since 2^20 > 1 000 000.
- Selection sort
- Repeatedly finds the smallest remaining item and swaps it into the next position; always O(n^2) comparisons.Example: [3, 1, 2]: swap 1 to the front, then 2 into place: [1, 2, 3].
- Insertion sort
- Builds a sorted section one item at a time by sliding each new item left into place; O(n^2) worst case but O(n) on nearly sorted data.Example: Sorting playing cards in your hand works this way.
- Merge sort
- Divide and conquer: split the list in half, sort each half recursively, then merge the sorted halves; O(n log n) time, O(n) extra memory, stable.Example: [5, 2, 4, 1] splits to [5, 2] and [4, 1], sorts to [2, 5] and [1, 4], merges to [1, 2, 4, 5].
- Nested loop complexity
- When a loop over n items contains another loop over n items, the inner body runs n x n times, giving O(n^2).Example: Checking every pair in a list for duplicates this way is O(n^2); using a set is O(n) on average.
Testing and debugging
- Syntax, runtime and logic errors
- Syntax errors stop code from running at all; runtime errors (exceptions) occur while running; logic errors run without crashing but give wrong results.Example: Missing colon: syntax. 1/0: ZeroDivisionError at runtime. Using + instead of *: logic.
- Exception handling
- try runs code that may fail; except catches a named exception type so the program can respond instead of crashing.Example: try: n = int(text) except ValueError: n = 0 handles input like 'abc'.
- Unit test
- A small automated check that one function gives the expected output for a chosen input; often written with assert or a testing framework.Example: assert add(2, 3) == 5 passes silently; a wrong result raises AssertionError.
- Edge cases
- Inputs at the boundaries of what a function must handle, where bugs often hide: empty inputs, single items, zero, negatives, duplicates, very large values.Example: Test a max function on [], [7] and [-3, -1].
- Debugging strategies
- Reproduce the bug, narrow down where it happens (print statements or a debugger with breakpoints), form a hypothesis, fix, then retest.Example: Printing a loop variable each pass often reveals an off-by-one error.