Keentune

Python curriculum

23 chapters
·
249 concepts
·
free
Everything the adaptive question bank can teach and test in Python, from foundations through advanced practice. Work through it in order, or start practising and let the questions find your level.
New here? Read the Python guide
A free 18-minute primer — the mental model, the mistakes beginners make, and what to practise first.
A. Objects, names and the data model
is compares identity, == dispatches to __eq__
assignment binds a name, it never copies an object
which builtins can change in place, and why it matters for aliasing
cached objects make is accidentally "work"
__bool__, falling back to __len__, else truthy
__hash__/__eq__ must agree; mutating a key corrupts a dict
refcounts plus a cycle collector, and what del actually does
copy vs deepcopy vs slicing, and shared nested state
the debugging representation vs the human one, and the fallback
functions, classes and modules are first-class values
B. Numbers and arithmetic
/ always floats, // floors toward negative infinity
% takes the sign of the divisor, unlike C
Python ints do not overflow; the cost is time, not wraparound
0.1 + 0.2 != 0.3, and what to do instead
banker's rounding, and why round(2.5) is 2
decimal.Decimal context, precision and exact base-10
fractions.Fraction for exact ratios
exact cross-type comparison and the equality/hash rule
shifts and masks on arbitrary-precision ints
math.isclose, math.fsum, ** vs math.pow
C. Sequences: list, tuple, range
a[start:stop:step] is half-open and never raises
counting from the end, and the -0 trap
assigning to a slice can change the list's length
[[0]*3]*3 shares rows
skipped elements and the copy-or-rebuild fix
in-place returning None vs a new list
key=, stability, and decorate-sort-undecorate
a tuple holding a list is still mutable inside
the comma, not the parentheses, makes the tuple
a, *rest = xs, swapping, and nested unpacking
front insertion is O(n) on a list, O(1) on a deque
a range object is not a list, and supports containment in O(1)
D. Strings and text
building strings in a loop vs str.join
expressions, = for debugging, nested quotes
width, alignment, precision, thousands separators
the whitespace-collapsing default vs an explicit separator
strip("abc") removes characters, not a prefix
the correct prefix/suffix tools
text is not bytes; encode/decode and error handlers
NFC vs NFD, and why visually equal strings compare unequal
case-insensitive comparison beyond ASCII
table-driven character mapping
dedent, wrap, and what triple quotes really keep
t-strings are not str; the injection-safety model
E. Bytes and binary data
immutable vs mutable binary buffers
b"abc"[0] is 97, not b"a"
slicing without copying, and buffer lifetimes
fixed-width binary layout, endianness and alignment
transport encoding vs secrecy
"rb" vs "r", newline translation, and encoding=
hexdigest vs digest, and why hashing needs bytes
explicit byte order when serializing integers
F. Dicts, sets and hashing
ordered since 3.7, and what that does not promise
missing-key behavior of each
reading a missing key CREATES it
keys()/items() reflect later mutation
|, |= and {**a, **b} precedence
duplicate keys silently collapse
union/intersection/difference, and operator vs method typing
hashable sets for use inside sets and dicts
iteration order is unspecified, not shuffled
multiset counting and tie behavior
average O(1), worst-case degradation
in is O(1) on a dict/set, O(n) on a list
G. Control flow and comprehensions
else runs when the loop was not break-ed
where if goes and what it does
the loops read left to right, outermost first
the loop variable does not leak (unlike Python 2)
laziness, memory, and single consumption
assignment expressions and where they are legal
a if cond else b and its precedence traps
and/or return an operand, not a bool
a < b < c evaluates b once
match/case, capture vs literal, guards
a bare name captures; only a dotted name compares
indices without counters; zip(strict=True)
H. Functions, arguments and scope
defaults evaluate once at definition
/ and * in a signature
packing at definition, unpacking at the call site
defaults, then binding, then body
local, enclosing, global, builtin resolution order
rebinding vs mutating an outer name
a later assignment makes the whole name local
passing, returning and storing functions
an expression, not a statement; when a def is clearer
a function without return yields None
sys.setrecursionlimit, and why Python has no TCO
the runtime-visible contract
I. Closures, decorators and functools
closures capture the variable, not its value
what a closure actually stores
@f is name = f(name)
the extra factory layer
preserving __name__, __doc__ and the signature
memoization, hashable arguments, and cache eviction
per-instance lazy attributes and their invalidation cost
functools.partial vs a lambda
type-based dispatch without an if-chain
folds vs an explicit loop or sum
J. Iterators, generators and itertools
__iter__ vs __next__, and why an iterator is one-shot
how for ends, and the next(it, default) form
yield suspends and resumes with state intact
a consumed generator silently yields nothing
delegating to a sub-generator, including its return value
two-way generators and cleanup
streaming a large file instead of materializing it
slicing, concatenating and duplicating iterators
groups are contiguous runs, not a GROUP BY
which one a counting problem needs
the shortest input ends the zip unless strict=True
implementing the protocol on your own type
K. Classes, attributes and descriptors
the shared-mutable-class-attribute bug
bound methods and what self really is
__new__ allocates, __init__ initializes
C3 linearization; super() follows the MRO, not the parent
every class in the chain must call super()
alternative constructors vs namespaced functions
computed attributes without changing the call site
__get__/__set__, and how property is built from it
memory savings, and the features __slots__ removes
__add__, __radd__, and NotImplemented
defining __eq__ sets __hash__ to None
nominal ABCs vs structural Protocol
__private becomes _Class__private
the fallback hook vs the intercept-everything hook
type as a class factory, and when __init_subclass__ is enough
L. Dataclasses, enums and records
what @dataclass writes for you
field(default_factory=...) and the error you get without it
immutability, hashability and __post_init__
order=True compares fields in declaration order
tuple-compatible vs attribute-first records
dict shape checking vs a real class
members, values, aliases and identity comparison
interoperating with ints/strings, and the risk
generated values and bitwise flag sets
M. Exceptions and error handling
catching Exception vs BaseException
swallowing KeyboardInterrupt and SystemExit
what runs when, including on return
a return in finally discards the exception
__cause__ vs __context__ in the traceback
inherit from Exception, carry structured data
try/except vs pre-checking, and the race between them
except* and errors from concurrent tasks
the multi-exception form and its as caveat
the warnings module and its filters
-O strips asserts
N. Context managers and resource cleanup
__enter__/__exit__ and the return value
returning True swallows the error
the yield-based generator form
one with, and parenthesized groups
a dynamic number of managers
small, explicit cleanup helpers
CPython refcounting is not a portable guarantee
which managers survive nesting or a second use
O. Modules, packages and imports
sys.modules caching and import side effects
from .mod import x and where it is legal
why scripts need it, especially with multiprocessing
the partially-initialized-module error and the fixes
with and without __init__.py
how the interpreter finds a module, and shadowing stdlib
what __all__ actually controls
importing by name, and reloading caveats
import time as startup cost, and deferring it
P. Typing and annotations
the runtime ignores them; a checker does not
X | None is not the same as having a default
accept the narrowest capability you need
why list[Dog] is not a list[Animal]
the escape hatch, the top type, the bottom type
the def f[T](…) / class C[T] syntax
duck typing a checker can verify
constraining values, not just types
optional keys in a dict shape
several signatures, one implementation
teaching the checker what a predicate proves
lazy evaluation on access, and forward references
a distinct type for a checker vs a readable synonym
Q. Concurrency: threads, processes and the GIL
one thread executes bytecode at a time
threads help with waiting, processes with computing
why += 1 is not atomic
mutual exclusion, and re-entering your own lock
the classic two-lock inversion
thread-safe producer/consumer without shared state
pickling costs and which executor fits
fork vs spawn, and what is inherited
joining vs abandoning work in flight
per-thread data instead of locking
the no-GIL build is a separate build, not the default
isolation as a third concurrency tier
R. asyncio and async/await
cooperative scheduling on one thread
where await is legal, and top-level await
an un-awaited coroutine never runs
concurrency comes from scheduling, not from async
create_task schedules; the coroutine alone does not
scoped tasks and grouped failure
CancelledError is delivered, not returned
asyncio.timeout vs wait_for, and what gets cancelled
one sync call stalls every task; to_thread
async for, async with, and their protocols
bounding an async pipeline
finding the stall
S. Files, paths and I/O
/ joining, and why string concatenation breaks
w destroys, a appends, x refuses to clobber
the platform default is a portability bug
universal newlines and when to disable translation
why output can appear out of order
iterate lines instead of read()
safe temporary files, and the mkstemp race
low-level syscall wrappers vs high-level file operations
pattern matching over a tree, and hidden-file behavior
streams, piping and text vs binary access
T. Standard-library toolkit
the right container for the access pattern
a naive datetime has no timezone, and compares badly
IANA zones, DST transitions, and UTC storage
tuples become lists, keys become strings
search vs match vs fullmatch
quantifier appetite, and re.DOTALL/re.MULTILINE
why manual split(",") corrupts data
arguments vs options, types and defaults
levels, handlers, and configuring the root logger once
reading the environment safely, with defaults
argument lists over shell=True
reproducible pseudo-randomness vs cryptographic randomness
sorted insertion and priority queues
placeholders instead of string-built SQL
the stdlib Zstandard module and where it beats gzip
the modern REPL, and what ships in the box before you add a dependency
U. Testing, debugging and performance
where assert belongs
per-test isolation and shared state
patch where the name is looked up, not where it is defined
one behavior, many inputs
asserting the raise, the type and the message
executable documentation and its limits
measuring instead of guessing
profiling before optimizing
the built-in debugger entry point
finding what actually holds memory
V. Packaging, environments and tooling
isolation, activation, and what pip install targets
the declarative project metadata standard
version ranges, extras and markers
a lock file for applications, ranges for libraries
developing a package while it is importable
built distributions vs source, and why it matters on install
exposing a command-line interface
the two names are unrelated
W. Language evolution and version gates
what a PEP is, and how a feature becomes a language rule
opting in early, and why they eventually become no-ops
reading a DeprecationWarning as a deadline
a feature's minimum version is part of the answer
which behaviors are language, which are CPython
experimental, opt-in, and not a semantic change
Keentune is not affiliated with or endorsed by the organizations whose documentation informs these maps.
All about Python practice
Also on your phone
All exam, test, and product names and trademarks are the property of their respective owners and are used here for identification and reference only. Keentune is independent study practice — not affiliated with, authorized, or endorsed by any of these organizations.
© 2026 SportaApp LLC