Back
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 practicing and let the questions find your level.
Start practicing Python
New here? Read the Python guide A free 18-minute primer — the mental model, the mistakes beginners make, and what to practice 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.
Practice this section →
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 .
Practice this section →
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.
•
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).
Practice this section →
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.
Practice this section →
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.
Practice this section →
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.
Practice this section →
G. Control flow and comprehensions •
else runs when the loop was not break -ed.
•
In a comprehension, 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) .
Practice this section →
H. Functions, arguments and scope •
Defaults evaluate once at definition.
•
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.
Practice this section →
I. Closures, decorators and functools •
Closures capture the variable, not its value.
•
What a closure actually stores.
•
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 .
Practice this section →
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.
•
product , permutations and combinations : which one a counting problem needs.
•
The shortest input ends the zip unless strict=True .
•
Implementing the protocol on your own type.
Practice this section →
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.
Practice this section →
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.
Practice this section →
M. Exceptions and error handling •
Catching Exception vs BaseException .
•
Swallowing KeyboardInterrupt and SystemExit .
•
else and finally : 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.
Practice this section →
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.
•
Reentrant versus reusable context managers: which survive nesting or a second use.
Practice this section →
O. Modules, packages and imports •
sys.modules caching and import side effects.
•
from.mod import x and where it is legal.
•
The __name__ == "__main__" guard: why scripts need it, especially with multiprocessing.
•
The partially-initialized-module error and the fixes.
•
Packages 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.
Practice this section →
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.
Practice this section →
Q. Concurrency: threads, processes and the GIL •
One thread executes bytecode at a time.
•
Threads help with waiting, processes with computing.
•
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.
Practice this section →
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 canceled.
•
One sync call stalls every task; to_thread .
•
async for , async with , and their protocols.
•
Bounding an async pipeline.
Practice this section →
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.
Practice this section →
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.
Practice this section →
U. Testing, debugging and performance •
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.
Practice this section →
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.
Practice this section →
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.
•
CPython versus other implementations: which behaviors are language, which are CPython.
•
Experimental, opt-in, and not a semantic change.
Practice this section →
Keentune is not affiliated with or endorsed by the organizations whose documentation informs these maps.
Start practicing Python
All about Python practice
Browse all free study guides
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