Glossary
Concise definitions for terms used across the lessons and reference. Each entry links to the lesson it's taught in, where one exists.
Aliasing
When two names refer to the same mutable object, so a change made through one name is visible through the other.
alias = original doesn’t copy original — it gives the same object a second name. For an
immutable value this is invisible, since nothing can change it anyway. For a mutable one (a
list, dict, or set), it means alias.append(x) and original.append(x) do the exact same
thing. original.copy() (or list(original), or a full slice original[:]) creates an
independent object instead, breaking the alias.
Taught in: Collections and Iteration
Assertion
A debugging check (assert condition, "message") that raises AssertionError if condition is false — meant to catch programmer bugs during development, not to validate real-world input.
An assertion documents an invariant the code assumes is always true — “this list is never empty
here,” “this value was already validated.” It’s the wrong tool for rejecting bad user input:
python -O strips every assert statement from a program entirely, so validation that must
always run belongs in an explicit if ...: raise ValueError(...) instead.
Taught in: Errors and Debugging
Binding
The association between a name and the object it currently refers to, created by assignment.
Thinking of a variable as a labeled box that holds a value leads to wrong predictions in Python.
The accurate picture: a name is a label attached to an object that lives independently of the
name. Assignment moves the label, not the object — a = b attaches the label a to whatever
object b was already labeling, and does not duplicate anything.
Taught in: Names, Values, and Assignment
Code point
A single unit of the Unicode character set that a Python str is made of — not always the same as what a person would call one visible character.
len() on a str counts code points, which usually matches “characters” for plain text but can
diverge for accented letters built from a combining mark, emoji with modifiers, or other symbols
assembled from more than one code point — a case this site doesn’t dwell on early, but worth
knowing exists before trusting len() as a stand-in for “how many characters will this look like.”
Taught in: Strings and Text
Composition
Building a class by holding instances of other classes as attributes, rather than inheriting from them — usually the more flexible default over inheritance.
A Library that has a list of Book objects (composition) is more flexible than a Library
that somehow is a Book (inheritance) — the relationship here is clearly “holds,” not “is a
kind of.” Composition is usually the safer default; inheritance earns its place when there’s a
genuine, stable is-a relationship the whole design depends on.
Taught in: Classes and Data Modeling
Comprehension
A compact expression that builds a list, dict, or set by looping over an iterable and optionally filtering it, e.g. [x * 2 for x in range(5)].
A comprehension is an expression, not a statement — it produces a new collection as a value,
rather than a loop that mutates one you already built. [name for name, qty in pairs if qty < 10]
reads as “the name, for each (name, qty) pair, where qty is under 10” — the same result as an
explicit for loop that appends to a list, written more compactly once that longer form is
already familiar.
Taught in: Collections and Iteration
Context manager
An object usable with with that guarantees its setup and cleanup code run together, even if an exception occurs — most commonly an open file.
with open(path) as f: is the example almost everyone meets first: opening is the setup, closing
is the cleanup, and with guarantees the file gets closed when the block ends — even if the code
inside raised an exception partway through.
Taught in: Files and Structured Data
Duck typing
Judging whether an object fits a role by whether it has the right methods or attributes, not by its declared type — "if it walks like a duck and quacks like a duck."
A function that calls .read() on its argument works with an open file, a network response, or
any other object exposing a .read() method — it never checks isinstance(arg, SomeSpecificType)
first. Python favors this over requiring a specific base class, which is also why protocols like
__repr__/__eq__ and the iterator protocol matter so much: they’re exactly the “right methods”
duck typing checks for.
Taught in: Classes and Data Modeling
Encoding
A mapping between text (Unicode code points) and the bytes used to represent it on disk or over a network — UTF-8 is the overwhelming default.
A Python str has no encoding — it’s already a sequence of code points. An encoding only enters
the picture at the boundary where text becomes bytes (str.encode(encoding)) or bytes become
text again (bytes.decode(encoding)). Using the wrong encoding at either boundary is what produces
garbled text or a UnicodeDecodeError.
Taught in: Strings and Text
Environment variable
A named value set outside the program (by the OS or shell) and read via os.environ — the standard way to pass configuration and secrets without hardcoding them in source.
os.environ["API_KEY"] (or os.environ.get("API_KEY") for an optional one) reads a value the
program’s environment provides rather than one written into the source code — the standard way to
keep secrets (API keys, database passwords) and per-deployment configuration out of version
control entirely.
Taught in: Files and Structured Data
Fixture
A pytest function that sets up (and cleans up) something a test needs — a temp directory, sample data, a database connection — declared as a parameter the test function requests by name.
pytest’s built-in tmp_path fixture (a parameter named tmp_path on a test function) hands the
test a fresh, empty temporary directory, deleted automatically afterward — the standard way to
test file-writing code without leaving files behind or depending on a real, shared location on
disk.
Taught in: Testing and Quality
Flaky test
A test that sometimes passes and sometimes fails without any code change — usually caused by relying on real time, randomness, network access, or test-execution order.
A test asserting on datetime.now(), an unseeded random number, a live network call, or state left
over from a different test are the classic causes. A deterministic test controls every source of
variation explicitly (a fixed/injected time, a seeded random generator, a fake instead of a real
network call) so the same code always produces the same test result.
Taught in: Testing and Quality
Guard clause
An early return, break, or continue that handles an edge case immediately, so the rest of a function or loop doesn't have to nest inside an else.
Checking for an invalid or edge-case input first and returning immediately — rather than wrapping
the “normal” logic in an if valid: ... block — keeps the common path at the outer indentation
level, which stays readable as a function grows.
Taught in: Control Flow
Identity
Which specific object a name refers to, checked with is and reported by id() — distinct from equality, which compares value with ==.
Two names can be equal (==, same value) without being identical (is, the same object) — [1, 2] == [1, 2] is True even though they’re two separate list objects. Identity is strictly stronger
than equality: identical objects are always equal, but equal objects are not always identical.
Taught in: Names, Values, and Assignment
Interpreter
The program that reads and executes Python source code, one statement at a time, rather than compiling it to a standalone binary ahead of time.
When this site says “the interpreter,” it means the running python process itself — most
commonly CPython, the reference implementation you get from python.org. The interpreter compiles
source to an internal bytecode form and then executes that bytecode; “interpreted” describes the
absence of a separate ahead-of-time compile-to-native-binary step that a language like C requires,
not a claim that Python skips compilation entirely.
Taught in: Orientation: Running and Reading Python
Logging
Recording diagnostic messages about a running program's behavior, with severity levels, instead of relying only on print statements.
The standard library’s logging module supports severity levels (debug, info, warning,
error, critical) that can be filtered without editing the code that emits them, and — unlike
print — writes to stderr by default, keeping diagnostic noise separate from a program’s actual
output on stdout.
Taught in: Errors and Debugging
Mutability
Whether an object's state can change after creation without changing its identity. Lists and dicts are mutable; strings, tuples, and numbers are not.
A mutable object (a list, dict, or set, or most custom objects) can be changed in place —
my_list.append(x) modifies the same object every other name bound to it also sees. An immutable
object (an int, float, str, tuple, or frozenset) can never change after creation; an
operation that looks like it changes one, such as s = s + "!", actually builds a new object and
rebinds the name to it, leaving the original untouched.
Taught in: Names, Values, and Assignment
Namespace
A mapping from names to objects — a module, a class, a function call, and more all have their own. The same name can exist in different namespaces without colliding.
math.pi and a local variable named pi never collide, because math’s namespace and the
current function’s local namespace are separate mappings — the module name (math.) is what
selects which namespace to look pi up in. Every module is itself a namespace, which is exactly
why importing one doesn’t dump all its names directly into the importer’s own namespace.
Taught in: Modules, Packages, and Environments
REPL
Read-Eval-Print Loop — an interactive prompt that reads one statement, runs it immediately, and shows its result, in a loop.
Starting python with no file argument opens the REPL, recognizable by its >>> prompt. It’s the
fastest way to check what a short expression does, but it evaluates one statement (or block) at a
time and doesn’t save anything to disk — code meant to be run again later belongs in a script file
instead.
Taught in: Orientation: Running and Reading Python
Scope
The region of code where a name binding is visible — local (inside a function), enclosing, global (module-level), or built-in.
Python looks up a name using the LEGB order: Local (the current function), Enclosing (an outer
function, for a nested one), Global (the module), then Built-in (len, print, and friends). A
name assigned inside a function is local by default; the global keyword (as increment() uses
in this lesson’s example) explicitly opts into reading and writing a module-level name instead.
Taught in: Functions and Scope
Side effect
Any observable change a function makes beyond returning a value — mutating an argument, printing, writing a file, changing a global. A pure function has none.
A pure function’s output depends only on its arguments, and calling it changes nothing else about the program’s state — calling it twice with the same arguments always gives the same result. Pure functions are easier to test and reason about in isolation; side effects are often necessary (printing output, persisting data) but worth keeping deliberate and visible rather than incidental.
Taught in: Functions and Scope
Traceback
The report Python prints when an exception propagates all the way up without being caught, showing the chain of calls that led to it.
A traceback lists frames from oldest call to most recent, and — this is the part worth internalizing early — the most useful information is almost always at the bottom: the last line names the exception type and message, and the line just above it points at the exact source line where it was raised. Reading a traceback bottom-up, rather than top-down, is the fastest path to the actual cause.
Taught in: Orientation: Running and Reading Python
Truthiness
Whether Python treats a value as True or False in a boolean context (an if, a while, an and/or chain) without an explicit comparison.
0, 0.0, None, False, and every empty collection ("", [], {}, set()) are falsy;
nearly everything else is truthy. if items: is a common, idiomatic way to check “is this
collection non-empty” without spelling out if len(items) > 0:.
Taught in: Control Flow
Virtual environment
An isolated Python installation with its own set of installed packages, kept separate from the system Python and other projects.
Created with python -m venv .venv (or uv sync, which does the equivalent automatically from a
pyproject.toml), a virtual environment means pip install (or uv add) affects only that one
project — never the system-wide Python, and never another project’s own dependencies.
Taught in: Modules, Packages, and Environments