Abstraction

Deliberately choosing which details of a real-world thing matter for a problem, and leaving the rest out.

Abstraction means representing only the details relevant to the problem at hand, on purpose — not because the other details don’t exist, but because the problem doesn’t need them. The same real-world thing can be abstracted differently depending on what question is being asked about it.

class_size = 24                              # abstraction: only the count matters
student_names = ["Ada", "Grace", "Linus"]     # abstraction: identity and order matter too

Both are valid models of “a classroom” — which one is right depends entirely on the problem being solved.

Taught in: Abstraction and Modeling

Algorithm

A finite, precise sequence of steps that solves a problem.

An algorithm is a plan for solving a problem, described precisely enough that it could be followed by hand — before it’s translated into any particular programming language. “Look through the list and remember the biggest number seen so far” is an algorithm; the Python code that implements it is just one expression of it.

Taught in: Pseudocode and Tracing

Assertion

A statement that checks a claim about a program's behavior and fails loudly if it's wrong.

assert turns a worked example into a repeatable, automatic check. If the expression after assert is False, Python raises an error immediately, pointing at exactly that line — rather than letting a wrong value silently flow through the rest of the program.

def double(n):
    return n * 2

assert double(3) == 6
assert double(0) == 0   # an edge case, checked too

Taught in: Debugging and Testing

Assignment

The operation, written with =, that makes a name refer to the result of an expression.

Assignment evaluates the expression on the right of =, then makes the name on the left refer to that result. It is never a claim that two things are equal — Python uses a separate operator, ==, for that.

x = 5        # assignment: x now refers to 5
x = x + 1    # right side evaluates to 6 first, then x refers to 6
print(x == 6)  # comparison: True

Taught in: Variables and State

Attribute

A piece of state stored on an object, accessed with a dot, like book.title.

An attribute is a named piece of state that belongs to a specific object. Each instance has its own copies of its attributes, independent of every other instance of the same class.

book1 = LibraryBook("Dune")
print(book1.title)        # "Dune" — an attribute, accessed with a dot
book1.is_on_loan = True    # attributes can be set directly, too

Taught in: Objects and Classes

Boolean

A value that is either True or False.

A boolean is a value that represents one of exactly two states: True or False (capitalized, no quotes — quoting them would make a string instead). Booleans are what conditions evaluate to.

in_stock = True
print(type(in_stock))   # <class 'bool'>
print(5 > 3)             # True — a comparison is an expression too

Taught in: Values and Types, Conditions

Class

A blueprint that defines a family of objects sharing the same attributes and methods.

A class defines what every object built from it will have — which attributes it starts with, and which methods it supports. The class itself isn’t a book; it’s the blueprint that every individual book object is built from.

class LibraryBook:
    def __init__(self, title):
        self.title = title
        self.is_on_loan = False

Taught in: Objects and Classes

Class diagram

A simple sketch of classes and how they relate — is-a or has-a — used to communicate a design before writing code.

A class diagram sketches a design at a glance: boxes for classes, labeled arrows for how they relate. Two relationships cover most designs in this course — is-a (inheritance) and has-a (composition).

[LibraryBook]
      ^
      | is-a
      |
[ReferenceBook]

[Member] --has-a--> [Account]

A quick diagram like this catches a design mistake — the wrong relationship, or the arrow pointing the wrong way — before any of it becomes code.

Taught in: Class Relationships and Simple Diagrams

Composition

Building an object out of other objects, each responsible for its own part, rather than one class doing everything.

Composition means an object holds another object as one of its attributes and delegates work to it, instead of reimplementing that object’s behavior itself. It’s a natural fit for “has-a” relationships: a member has an account, rather than is an account.

class Member:
    def __init__(self, name, starting_balance):
        self.account = Account(starting_balance)   # composed, not copied

    def pay_fine(self, amount):
        return self.account.withdraw(amount)        # delegates to it

Taught in: Composition

Condition

A boolean expression that a program uses to choose which code runs.

A condition is an expression that evaluates to True or False, used by an if statement (or a while loop) to decide what happens next.

temperature = 15
if temperature < 0:
    print("Freezing")
else:
    print("Not freezing")

Taught in: Conditions

Decomposition

Breaking a large or vague problem into smaller, independently understandable pieces.

Decomposition means splitting a problem into smaller subproblems, each with its own clear responsibility, input, and output — small enough to understand, implement, and check on its own. In Python, each piece usually becomes its own function.

def subtotal(prices):
    return sum(prices)

def tax(subtotal, rate):
    return subtotal * rate

def total(subtotal, tax):
    return subtotal + tax

Three small, individually testable pieces, instead of one long block that does all three things at once.

Taught in: Problem Decomposition

Dictionary

A collection that maps keys to values, so you can look values up by name instead of position.

A dictionary stores key-value pairs. Instead of accessing an item by numeric position (as a list does), you look it up by its key.

prices = {"coffee": 4.5, "tea": 3.0}
print(prices["coffee"])   # 4.5

Taught in: Lists and Dictionaries

Edge case

An unusual or boundary input a solution must still handle correctly, not just the typical case.

An edge case is an input at the boundary of what a solution expects — an empty list, a single item, a zero, a duplicate, the very first or last position — rather than a typical, “normal-looking” input. A solution that only accounts for the typical case often runs without error on an edge case and simply produces the wrong answer, a logic error rather than a crash.

def first(items):
    return items[0]

first([1, 2, 3])   # fine
first([])           # the edge case: raises IndexError

Taught in: Inputs, Outputs, Constraints, and Edge Cases

Encapsulation

Protecting an object's internal state by funneling changes to it through methods that can enforce valid values.

Encapsulation means an object’s state changes only through its methods, which can enforce rules a direct assignment can’t — like refusing an overdraft. A leading underscore, as in _balance, is Python’s convention for signaling “treat this as internal,” but it is only a signal: Python does not actually prevent code from setting it directly.

account.withdraw(1000000)   # blocked — the method checks the balance first
account._balance = -1000000  # not blocked — Python allows this anyway

Taught in: Encapsulation

Expression

A piece of code that evaluates to a value.

An expression is anything Python can reduce down to a single value: 2 + 2, price * quantity, and even a lone value like "hi" are all expressions. Expressions can be combined — the right-hand side of an assignment is always an expression, evaluated first before anything is stored.

total = 3 * 4 + 1   # the expression 3 * 4 + 1 evaluates to 13
print(total)         # 13

Taught in: Values and Types, Expressions

Float

A number value with a decimal point.

A float is a number written with a decimal point, even if that point is followed by a zero. Python’s floating-point type is written float.

price = 4.50
print(type(price))   # <class 'float'>

Mixing an integer and a float in an operation (3 + 4.5) works and produces a float — unlike mixing a string and a number.

Taught in: Values and Types

Function

A named, reusable block of code that packages a transformation behind an interface.

A function groups a sequence of steps under a name, so the steps can be reused without repeating them. Code that uses a function only needs to know what goes in and what comes out — not how the inside works.

def double(number):
    return number * 2

print(double(5))   # 10

Taught in: Functions

Graph

Nodes connected by edges in any pattern, with no restriction to a hierarchy — cycles and multiple paths are allowed.

A graph connects nodes to each other with no hierarchy required — a social network of friendships, or a map of roads between cities. Unlike a tree, a graph can have cycles (a path that loops back on itself) and more than one path between two nodes.

graph = {
    "Ada": ["Grace", "Linus"],
    "Grace": ["Ada", "Margaret"],
    "Linus": ["Ada"],
    "Margaret": ["Grace"],
}

Each key’s list is that node’s direct connections. Traversing a graph safely means tracking which nodes have already been visited — without that, a cycle like Ada ↔ Grace can cause the same nodes to be revisited endlessly.

Taught in: Trees and Graphs as a First Look

Growth rate

How the amount of work a solution does increases as its input gets larger.

Growth rate describes how a solution’s work scales with input size, not how fast it runs on one particular input. A single loop over a collection is linear — doubling the input roughly doubles the work. A loop nested inside another loop, each running over the whole collection, is quadratic — doubling the input roughly quadruples the work.

for item in items:          # linear: one pass over items
    ...

for a in items:              # quadratic: a pass over items,
    for b in items:            # for every item in items
        ...

Taught in: Comparing Solutions

Index

The numeric position of an item within an ordered collection, starting at 0.

An index is a whole number that identifies an item’s position in a list or string. Python indexes start counting from 0, so the first item is at index 0, not 1.

letters = ["a", "b", "c"]
print(letters[0])    # "a" — first item
print(letters[2])    # "c" — last item, by position
print(letters[-1])   # "c" — last item, by negative index, from any length

A negative index counts backward from the end: -1 is always the last item, -2 the second-to-last, regardless of the collection’s length.

Taught in: Lists and Dictionaries

Inheritance

A relationship where one class automatically gets another's attributes and methods, and can override specific ones.

A subclass inherits every attribute and method its parent class defines, and can override any of them to specialize its behavior. It models an “is-a” relationship — a ReferenceBook is a LibraryBook — unlike composition’s “has-a.”

class ReferenceBook(LibraryBook):
    def borrow(self):   # overrides LibraryBook's borrow
        return False

ref = ReferenceBook("Encyclopedia")
print(ref.title)        # inherited from LibraryBook, unchanged
print(ref.borrow())      # overridden — always False

Taught in: Inheritance

Instance

One specific object built from a class, with its own independent state.

An instance is one particular object created from a class. Every instance shares the class’s methods, but each gets its own separate copy of its attributes — changing one instance’s state never affects another instance of the same class.

book1 = LibraryBook("Dune")
book2 = LibraryBook("Foundation")
# book1 and book2 are two independent instances of LibraryBook

Taught in: Objects and Classes

Integer

A whole number value, with no decimal point.

An integer is a whole number — positive, negative, or zero — with no fractional part. Python’s integer type is written int.

quantity = 3
print(type(quantity))   # <class 'int'>

Taught in: Values and Types

Interface

The methods and attributes other code is meant to rely on when using an object — its public contract.

An object’s interface is the part meant to be used from outside it — usually its methods. Code that only relies on an object’s interface keeps working even if the object’s internal implementation changes, because the interface’s behavior is what other code actually depends on, not how it’s achieved internally.

book.borrow()   # part of the interface — safe to rely on

Taught in: Interfaces and Public Behavior

len()

A built-in function that returns how many items a collection holds.

len() takes a collection — a list, a set, a dictionary, a string — and returns the number of items in it as an integer.

len([1, 2, 3])          # 3
len("hello")              # 5
len({"a", "b"})           # 2
len({"x": 1, "y": 2})     # 2 — the number of keys

Taught in: Sets and Uniqueness

List

An ordered, changeable collection of values, accessed by position.

A list holds an ordered sequence of values, which can grow, shrink, or change after it’s created. Items are accessed by their position, called an index, starting from 0.

fruits = ["apple", "banana", "cherry"]
print(fruits[0])   # "apple"
fruits.append("date")

Taught in: Lists and Dictionaries

Logic error

A bug where the program runs without any error message but produces the wrong result.

A logic error is the hardest kind of bug to find, because nothing announces it — the program runs to completion and prints an answer that merely looks plausible, not one that’s actually correct.

def average(numbers):
    total = 0
    for number in numbers:
        total = total + number
    return total   # bug: never divided by the count

print(average([2, 4, 6]))   # prints 12, not the average, 4

Since there’s no error message to point at a line, finding a logic error usually means checking the actual output against a hand-worked example — which is exactly what an assertion automates.

Taught in: Debugging and Testing

Loop

A block of code that repeats, either a set number of times or until a condition changes.

A loop repeats a block of steps instead of writing them out multiple times. Python’s for loop repeats once per item in a sequence; its while loop repeats as long as a condition stays true.

for count in range(3):
    print(count)
# prints 0, 1, 2

Taught in: Loops

Method

A function defined inside a class, describing something its objects can do.

A method is a function that belongs to a class, describing one of its objects’ behaviors. Calling a method always acts on one particular instance — book1.borrow() runs the borrow method against book1 specifically, not every LibraryBook.

class LibraryBook:
    def borrow(self):
        self.is_on_loan = True

book1.borrow()   # only book1 changes

Taught in: Objects and Classes

Model

A concrete representation of a real-world scenario, built by abstracting away irrelevant detail.

A model is what results from applying abstraction to a real-world scenario — a concrete representation, usually built from values and existing structures, that captures only what a particular problem needs.

# a model of "today's temperatures," built only from what a
# "what was the highest?" problem actually needs
temperatures = [61, 58, 64, 59]

Taught in: Abstraction and Modeling

Mutability

Whether a value can be changed in place after it's created, rather than replaced entirely.

A mutable value, such as a list, can be changed in place — the same value keeps its identity while its contents change. An immutable value, such as an integer or string, can never change; “changing” a variable holding one really means making the name refer to a different value.

numbers = [1, 2, 3]
numbers.append(4)   # the same list, now with 4 items — mutated in place

x = 1
x = x + 1            # not mutation: x now refers to a different, new int

Taught in: Mutability and References

Node

One element of a linked structure, holding a value together with a reference to the next node.

A node bundles a value with a reference to the next node in the chain (or None, if it’s the last one). Nodes don’t need to sit next to each other in memory the way a list’s items do — following the chain of next references is what connects them.

first = {"value": 10, "next": None}
second = {"value": 20, "next": None}
first["next"] = second   # first is now linked to second

Taught in: Linked Structures as a Mental Model

Object

A bundle of state and behavior treated as one thing, with its own identity.

An object combines state (the information it currently holds) and behavior (what it can do) under one name, and has its own identity — two objects can hold identical information and still be two separate things. A library book is a good example before any code exists: it has state (its title, whether it’s on loan) and behavior (it can be borrowed).

print(type([1, 2, 3]))   # a list is an object too — <class 'list'>

Taught in: Objects and Classes

Operator

A symbol like + or * that combines one or more values into a new value within an expression.

An operator combines values according to a rule: + adds numbers or joins strings, * multiplies, > compares. Operators are what turn a handful of values into a compound expression.

2 + 3 * 4   # two operators, + and *, combined into one expression

Taught in: Expressions

Parameter

A named input a function expects to receive when it is called.

A parameter is a placeholder name a function uses for a value it expects to be given. The actual value supplied at call time is called an argument.

def greet(name):   # name is the parameter
    print("Hello, " + name)

greet("Ada")        # "Ada" is the argument

Taught in: Functions

Polymorphism

Different objects responding to the same method call, each in its own way, without the caller checking which type it has.

Polymorphism means code can call the same method on objects of different types and get each one’s own behavior, without ever checking which specific type it’s dealing with.

animals = [Dog(), Cat(), Bird()]
for animal in animals:
    print(animal.speak())   # each animal's own speak() runs — no type-checking needed

Adding a new subclass that defines its own speak() makes it work in this loop automatically, with no changes to the loop itself.

Taught in: Polymorphism

Pseudocode

A plain-language, language-neutral description of an algorithm's steps.

Pseudocode describes an approach in structured plain language, without committing to any particular programming language’s syntax. It’s a way to plan and check a solution before worrying about how to write it in Python.

get a list of numbers
set biggest to the first number
for each remaining number:
    if it is bigger than biggest, set biggest to it
show biggest

Taught in: Pseudocode and Tracing

Queue

A first-in, first-out (FIFO) collection — the earliest item added is always the next one removed.

A queue always removes the item that was added earliest — first in, first out, like a line of people waiting. A Python list works as a queue using append() to add to the end and pop(0) to remove from the front.

line = []
line.append("Ada")
line.append("Grace")
print(line.pop(0))   # "Ada" — the first one to arrive, served first

Taught in: Stacks and Queues

Range

A sequence of whole numbers, most often used to control how many times a for loop repeats.

range(n) produces the whole numbers from 0 up to, but not including, n — a common source of off-by-one mistakes. range(a, b) starts at a instead of 0.

for i in range(3):
    print(i)
# prints 0, 1, 2 — three values, not including 3

Taught in: Loops

Reference

What a variable actually holds — a pointer to a value, not the value's own private copy.

A variable doesn’t hold a private copy of its value — it holds a reference to it. Assigning b = a makes b refer to the exact same object a does; if that object is mutable, a change made through either name is visible through both, because there’s only one object being referred to.

a = [1, 2, 3]
b = a          # b refers to the same list as a, not a copy
b.append(4)
print(a)        # [1, 2, 3, 4] — a sees the change too

Taught in: Mutability and References

Return value

The value a function sends back to the code that called it.

A function’s return statement specifies the value that a call to that function evaluates to. A function with no return statement returns a special empty value, None.

def square(n):
    return n * n

result = square(4)   # result refers to 16

Taught in: Functions

Runtime error

An error that happens while a program is running, after it has already started successfully.

A runtime error (Python calls these exceptions) happens partway through execution — the code was valid enough to start running, but something it tried to do during that particular run didn’t work.

numbers = [1, 2, 3]
print(numbers[5])
IndexError: list index out of range

Unlike a syntax error, a runtime error can depend on the specific input: numbers[5] only fails because this list happens to be too short.

Taught in: Debugging and Testing

Scope

The region of a program where a particular variable name can be seen and used.

Scope determines where a name is visible. A variable created inside a function normally only exists while that function is running, and can’t be seen from outside it — even if a variable with the same name exists elsewhere.

def set_total():
    total = 100   # only visible inside set_total

set_total()
print(total)   # NameError: total is not defined out here

Taught in: Scope

Set

A collection of unique values with no meaningful order, optimized for fast membership testing.

A set holds values with no duplicates and no guaranteed order — adding a value that’s already present has no effect. Sets are used for removing duplicates and for checking whether something is present, which stays fast even as a set grows large.

seen = {"ada", "grace"}
seen.add("ada")        # already present — no effect
print(len(seen))        # 2
print("grace" in seen)  # True

Taught in: Sets and Uniqueness

Stack

A last-in, first-out (LIFO) collection — the most recently added item is always the next one removed.

A stack always removes the item that was added most recently — last in, first out. A Python list works as a stack using append() to add to the end and pop() to remove from the end.

history = []
history.append("open file")
history.append("edit line 3")
print(history.pop())   # "edit line 3" — the most recent action, undone first

Taught in: Stacks and Queues

State

The current values of a program's variables at a given moment while it runs.

State is the snapshot of “what every variable currently refers to” at one point during a program’s execution. Tracing a program means writing down how its state changes, line by line.

total = 0             # state: total = 0
total = total + 5     # state: total = 5
total = total + 2     # state: total = 7

Taught in: Variables and State

String

A value that holds text, written between quotation marks.

A string is Python’s type for text: any characters between matching quotation marks. "5" is a string even though it looks numeric — the quotes are what make it text rather than a number.

name = "Ada"
print(type(name))   # <class 'str'>

Taught in: Values and Types

Syntax error

An error caused by code that doesn't follow the language's grammar rules, found before the program runs.

A syntax error means Python couldn’t understand the structure of your code at all — a missing colon, an unmatched parenthesis — so it refuses to run any of it. This is different from a TypeError, which only shows up while the program is running a specific line.

if True
    print("missing colon above")
SyntaxError: expected ':'

Taught in: Debugging and Testing

Trace

To simulate a program (or pseudocode) by hand, step by step, writing down how each variable's value changes.

Tracing means working through code line by line without running it, writing down what each variable refers to after every step that could change it. It’s used throughout this course to predict a program’s behavior and to catch mistakes before — or without — ever running the code.

total = 0
for n in [3, 5]:
    total = total + n
# trace: total = 0, then 3, then 8

Taught in: Pseudocode and Tracing

Traceback

The report Python prints when a runtime error goes unhandled, showing where it happened.

A traceback lists the chain of calls that led to an error, ending with the error’s type and message on the last line — read it from the bottom up: the last line says what went wrong, and the line above it points at exactly where.

Traceback (most recent call last):
  File "example.py", line 2, in <module>
    print(numbers[5])
IndexError: list index out of range

Here, IndexError: list index out of range is the problem, and line 2 is where it happened.

Taught in: Debugging and Testing

Tree

A hierarchy of nodes with one root, where every node except the root has exactly one parent.

A tree is a hierarchy: one root node at the top, each node possibly having children, and a node with no children called a leaf. Every node has exactly one parent (except the root, which has none) — a file system’s folders, or an org chart, are both trees.

root = {"value": "CEO", "children": []}
vp = {"value": "VP Engineering", "children": []}
root["children"] = [vp]

Every tree is a kind of graph, but not every graph is a tree — a graph can have cycles or nodes with more than one path between them, which a tree never does.

Taught in: Trees and Graphs as a First Look

Type

The category a value belongs to, which determines which operations on it are valid.

A type answers the question “what kind of value is this?” — integer, float, string, boolean, and many more. Python decides a value’s type automatically when the value is created, and that type never changes for that value.

print(type(42))     # <class 'int'>
print(type(42.0))   # <class 'float'>
print(type("42"))   # <class 'str'>

The type determines which operations make sense. Adding two integers is valid; adding an integer and a string raises a TypeError.

Taught in: Values and Types

TypeError

The error Python raises when an operation is used between types that don't support it.

A TypeError is Python’s way of refusing to guess. It happens when you try to use an operator or function on a type it wasn’t designed for — most commonly, mixing a string with a number using +.

"score: " + 10
TypeError: can only concatenate str (not "int") to str

The fix is usually to convert one value so both sides agree, for example with str(10).

Taught in: Values and Types

Value

A single piece of data a program works with, such as a number, a piece of text, or true/false.

Every piece of information a program manipulates — 42, "hello", True — is a value. A value always has exactly one type, which determines what you can do with it.

42        # an integer value
"hello"   # a string value
True      # a boolean value

Taught in: Values and Types

Variable

A name that refers to a value, which can be made to refer to a different value later.

A variable is a name a program uses to refer to a value. Reassigning a variable doesn’t change the old value — it makes the name refer to a new one instead.

score = 0
score = score + 10   # score now refers to 10, not 0
print(score)          # 10

Taught in: Variables and State