Language & library reference
Concept clusters →Every named result in this course, grouped by chapter. Each one links back to where it's derived.
Values, types, and operators
Rule
Floor division rounds down, and the remainder fits it
also known as: // and %, floor division and modulo, divmod
Formal. For integers a and b (with b not zero), a // b is
the largest whole number less than or equal to a / b: it rounds
toward negative infinity. a % b is defined so that
(a // b) * b + a % b == a always holds, which gives the remainder the
sign of the divisor b. divmod(a, b) returns both as a pair. A
single / is true division and always gives a float.
In plain English. // asks "how many whole times does b fit?",
and when the answer isn't whole it always steps DOWN, to the left on the
number line, even for negative numbers. % is whatever is left over so
that the pieces add back up to a.
Example. 7 // 2 is 3 and 7 % 2 is 1. -7 // 2 is -4, not
-3, and -7 % 2 is 1, because -4 * 2 + 1 is -7. 7 / 2 is
3.5, and 8 / 2 is 4.0.
Why this rule exists. Rounding down keeps % useful for clocks,
calendars and "every n-th" tests: n % 7 is always 0 to 6 for a
positive 7, whatever the sign of n.
Rule
What counts as false
also known as: truthiness, truthy and falsy values
Formal. When Python needs a true-or-false answer from a value (as
bool() gives, and as if and while will use in Chapter 4), these
are falsy:
False, None, zero of any number type (0, 0.0, 0j), and every
empty collection: the empty string "" now, and the empty lists,
tuples, dicts and sets of Chapter 5 later.
Everything else is truthy.
In plain English. Nothing, zero and empty mean false. Anything with something in it means true. A string is judged only by whether it is empty, never by what it says.
Example. bool("") is False, but bool(" "), bool("0") and
bool("False") are all True. bool(-1) is True, and bool(0.0)
is False.
Why this rule exists. It lets a test say what it means in a
few words: a test of name reads as "if a name was typed".
Rule
Python's operator precedence ladder
also known as: order of operations, operator precedence, associativity
Formal. From tightest to loosest: **; unary -x/+x; *, /,
//, %; +, -; comparisons (<, <=, ==, !=, in, is,
...); not; and; or. Operators on the same rung group left to
right, except **, which groups right to left. ** also binds
tighter than a unary minus on its LEFT. Parentheses beat all of it.
In plain English. Powers first, then multiplying and dividing, then
adding and subtracting, then comparing, then the logic words. Within
one rung, work left to right; the one exception is **, which works
right to left.
Example. 2 + 3 * 4 is 14. -3 ** 2 is -9, because it means
-(3 ** 2). 10 - 4 - 3 is 3, but 2 ** 3 ** 2 is 2 ** 9, which is
512.
Why this rule exists. It follows the order of operations from school arithmetic, so formulas read the way they're written on paper. When an expression is hard to read, parentheses cost nothing.
Strings and text processing
Rule
Indexes start at 0, and a slice stops before its end
also known as: zero-based indexing, half-open slices, negative indexes
Formal. In a sequence of length n, the items are at indexes 0
to n - 1; a negative index -k means index n - k, so -1 is the
last item. The slice s[i:j] contains the items at indexes i,
i + 1, ..., j - 1, so it has j - i items. A missing i means
the start and a missing j the end. A slice whose bounds run past the
end simply stops at the end, while a single index past the end is an
IndexError.
In plain English. Count the gaps between characters, starting at 0:
a slice takes everything between two gaps. -1 is "the last one",
-2 the one before it.
Example. With word = "python": word[0] is 'p', word[-1] is
'n', word[1:4] is 'yth' (three characters, 4 - 1), and
word[:2] + word[2:] is the whole word again.
Why this rule exists. Stopping before the end makes lengths and
joins add up: s[:k] has exactly k items, and s[:k] + s[k:] is
always s.
Decisions and repetition
Rule
range stops before its stop value
also known as: range(start, stop, step), half-open range
Formal. range(stop) produces 0, 1, ..., stop - 1.
range(start, stop) produces start, start + 1, ..., stop - 1.
range(start, stop, step) adds step each time and stops as soon as
the next value would reach or pass stop; a negative step counts
down. The stop value itself is never produced, so range(start, stop)
has stop - start values.
In plain English. range counts up to, but not including, the stop
number. range(5) means five numbers, starting from 0.
Example. range(5) produces 0, 1, 2, 3, 4. range(2, 6) produces
2, 3, 4, 5. range(1, 10, 3) produces 1, 4, 7, and range(5, 0, -1)
produces 5, 4, 3, 2, 1.
Why this rule exists. It matches zero-based indexing:
for i in range(len(word)) visits exactly the valid indexes of
word, and range(n) runs a loop exactly n times.
Collections
Rule
Mutable and immutable types
also known as: mutability, aliasing, shallow copy
Formal. An object of an immutable type (int, float,
bool, str, tuple, frozenset, None) can never change; every
operation that seems to change it builds a new object. An object of a
mutable type (list, dict, set, and most user-defined classes)
can be changed in place. Assignment b = a never copies: it binds a
second name to the same object, so a change made through one name of a
mutable object is seen through every name. a.copy(), list(a) and
a[:] make a shallow copy (a new outer object holding the same
items); copy.deepcopy(a) copies the nested objects too. Only
immutable values (and tuples of them) can be dict keys or set members.
In plain English. Some objects are set in stone and some are whiteboards. Two names can point at the same whiteboard, and then anyone writing on it changes what both see. Stone can't be written on, so sharing it is always safe.
Example. a = [1, 2]; b = a; b.append(3) leaves a as [1, 2, 3].
s = "hi"; t = s; t += "!" leaves s as "hi", because += built a
new string for t.
Why this rule exists. Sharing one object is fast and lets a function change a list it was given. Immutability is what makes a value safe to share and to use as a key.
Modules, packages, and project structure
Rule
The virtual-environment workflow
also known as: venv, python -m venv .venv, activate, deactivate
Formal. python -m venv .venv (or python3 -m venv .venv) creates
an isolated environment in the folder .venv, built from the Python
that ran the command. Activating it puts the environment's bin
(Windows: Scripts) folder first on PATH: source .venv/bin/activate
on macOS and Linux, .venv\Scripts\Activate.ps1 in PowerShell,
.venv\Scripts\activate.bat in Command Prompt. While it is active,
python means the environment's own interpreter, and the prompt shows
(.venv). deactivate restores PATH. Running the
environment's interpreter by its path (.venv/bin/python) uses it
without activating. The .venv folder is never committed to version
control.
In plain English. Each project gets its own private Python with its own installed packages. Make it once, switch it on in each new terminal, install into it, and switch it off when you're done.
Example. python3 -m venv .venv, then source .venv/bin/activate.
The prompt now starts with (.venv), and anything installed from here
on belongs to this project only.
Why this rule exists. Two projects often need different versions of the same package. Separate environments keep them from breaking each other and keep the system's own Python untouched.
Exceptions, debugging, and testing
Rule
The everyday built-in exceptions
also known as: NameError, TypeError, ValueError, IndexError, KeyError, ZeroDivisionError, AttributeError
Formal. NameError: a name that was never assigned.
TypeError: an operation applied to an object of the wrong type
("3" + 1, len(5)). ValueError: the right type but an unusable
value (int("cat")). IndexError: a position past the end of a list or string.
KeyError: a missing dict key. ZeroDivisionError: division or %
by zero. AttributeError: a method (or other name after a dot) the object
doesn't have. FileNotFoundError (a kind of OSError): opening a path that
doesn't exist. All of them are subclasses of Exception.
In plain English. The exception's name says what went wrong: a name Python never heard of, the wrong kind of thing, the right kind with a bad value, a position past the end, a missing key, division by zero, or a method the thing doesn't have.
Example. [1, 2, 3][3] raises IndexError; {"a": 1}["b"] raises
KeyError; int("4.5") raises ValueError; "total: " + 5 raises
TypeError.
Why this rule exists. The last line of a traceback names the exception first, so knowing these seven tells you what kind of mistake to look for before you read anything else.
Networking, APIs, and web data
Rule
The first digit of an HTTP status is its family
also known as: HTTP status code classes, 2xx 3xx 4xx 5xx
Formal. An HTTP status code's first digit is its family: 1xx
informational, 2xx success, 3xx redirection, 4xx client error, 5xx
server error. A 4xx response won't succeed if the same request is sent
again unchanged; a 5xx (and 429 Too Many Requests) may succeed later.
Success should be tested as a family, 200 <= code < 300, not as one
exact code.
In plain English. Read the first digit first. 2 means it worked, 3 means look somewhere else, 4 means your request was wrong, and 5 means the server went wrong.
Example. 200 OK, 201 Created, 204 No Content; 301 Moved Permanently, 304 Not Modified; 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests; 500 Internal Server Error, 503 Service Unavailable.
Why this rule exists. New codes can be added without breaking old programs, because every program can still act on the family.