PCAP-31-03 — Reading Guide
Everything you need to LEARN PCAP is free. This maps each of the five official blueprint blocks to the canonical readings that cover it — the Python docs, the tutorial, and the relevant PEPs — with a short “what to know for the exam” note on each. Read the block, drill its deck, then write the code.
How to use this: work each block in order (or front-load OOP + Miscellaneous — together they're over half the exam). Read the free source, note the exam traps called out below, then lock it in with the matching deck and the coding track. Everything with a Read free link is the full, official text.
Block 1 — Modules & Packages
How Python code is split across files and folders, and how import finds and runs it. Know the three import forms, what __name__ is, where Python searches (sys.path), what __init__.py and __all__ do, and the exam-favourite quirks of the math and random modules.
The core reading: the three import styles (import m / from m import name / import m as alias), the module search path, and the classic `if __name__ == '__main__':` guard — a module's __name__ is '__main__' when run directly and the module's own name when imported. Executing an imported module runs its top-level code exactly once (later imports reuse the cached object).
A package is a folder of modules marked by __init__.py. Learn dotted imports (import pkg.sub), and how __all__ controls exactly which names `from pkg import *` brings in. Single-underscore names are skipped by import *.
Exam traps live here: floor rounds toward -infinity, ceil toward +infinity, trunc toward zero; sqrt ALWAYS returns a float (sqrt(9) → 3.0). Also pi, e, and factorial.
The single most-tested distinction: randint(a, b) INCLUDES b, but randrange(a, b) EXCLUDES it (range semantics). choice() returns one element, sample() a subset, shuffle() reorders in place, seed() makes runs reproducible.
sys.path is the ordered list of directories import searches. The platform module is on the blueprint too: platform.system() returns 'Linux'/'Windows'/'Darwin', platform.machine()/processor() the hardware, platform.python_version() the interpreter version.
platform module referenceBlock 2 — Exceptions
Handling errors the Python way: the full try/except/else/finally shape, raising and re-raising, custom exceptions, assertions, and — heavily tested — where each built-in error sits in the class tree.
The main reading. Nail the clause semantics: else runs only when NO exception fired; finally ALWAYS runs (and a return in finally overrides one in try). Catch multiple types with a tuple `except (A, B):`; bind with `as e`; re-raise with a bare `raise`. Custom exceptions subclass Exception. `assert cond, msg` raises AssertionError when cond is falsy — and is disabled entirely under the -O flag.
Memorise the tree at the bottom of this page. BaseException is the true root; Exception is what you normally subclass and catch. Know that LookupError is the base of IndexError and KeyError; ArithmeticError is the base of ZeroDivisionError; ValueError vs TypeError (wrong value vs wrong type); FileNotFoundError is an OSError. A base class in an except clause must come AFTER its subclasses or it makes them unreachable.
How raise works with and without an argument, and `raise X from Y` for chaining. Caught instances carry .args (a tuple of the constructor arguments) and str(e) for the message.
Block 3 — Strings
Strings are immutable sequences of Unicode characters. The exam drills indexing/slicing, code points (ord/chr), lexicographic comparison, and the essential methods — usually as 'what does this print?' snippets.
The reference for every method the exam uses: split/join/strip/replace/find vs index (find returns -1, index raises)/count/startswith/upper/lower and the is* predicates. Remember strings are IMMUTABLE — every method returns a new string; s[0]='x' raises TypeError.
String methods (jump to the list)The gentle introduction to negative indexing (s[-1] is the last char), slicing (start-inclusive, stop-exclusive), steps and reversal (s[::-1]), and why slicing never raises on out-of-range bounds while plain indexing does.
ord('A') → 65 and chr(65) → 'A' are inverses; string comparison is by code point, so 'Z' (90) < 'a' (97). Skim the format() mini-language for {} placeholders and alignment/precision.
Format String SyntaxBlock 4 — Object-Oriented Programming
A full third of the score. Classes and instances, instance vs class variables (and shadowing), inheritance and the MRO, super(), encapsulation and name mangling, introspection, and the special ('dunder') methods that make operators and built-ins work on your objects.
The single most important reading for the exam. self, __init__, the difference between class variables (shared) and instance variables (per-object) and how assigning through self SHADOWS a class variable, inheritance, super().__init__(), and name mangling (__x inside class C becomes _C__x). Also scopes — the setup for closures/nonlocal in Block 5.
With class C(A, B), method lookup follows the Method Resolution Order — C, then bases left-to-right, then object — computed by C3 linearization. Read C.__mro__ to see it. This is a favourite 'which method runs?' question.
MRO — glossary definitionHow to make your objects behave like built-ins: __str__ (for print/str) vs __repr__ (debug/echo), __eq__ for ==, __add__ for +, __len__ for len(), __call__ to make an instance callable, __init__/__new__/__del__ lifecycle. Skim — you need recognition, not memorisation.
type(), isinstance(obj, Class) (True for subclasses; pass a tuple to test several), issubclass(A, B) (class-to-class), hasattr/getattr(with a default)/setattr, dir(), vars() (an object's __dict__). Know isinstance vs `type(x) is Class` (exact type only).
Block 5 — Miscellaneous — comprehensions, lambdas, closures, generators & I/O
The 'functional & lazy Python' block: list/dict/set comprehensions, lambdas with map/filter/sorted, closures and nonlocal, generators and the iterator protocol, and file I/O with the with statement. Second biggest block after OOP.
List, dict, and set comprehensions and nested/flattening forms. The key distinction the exam tests: a trailing `if` is a FILTER ([x for x in xs if cond]), while an `if/else` BEFORE the for is a per-element TRANSFORM.
A lambda is a single-EXPRESSION anonymous function. map/filter return lazy, single-pass iterators in Python 3 (wrap in list()). sorted(..., key=...) returns a NEW list; list.sort() mutates in place and returns None.
map / filter / sorted (built-ins)The iterator protocol is __iter__ + __next__ (raising StopIteration when done). A function with `yield` is a generator; (expr for x in xs) is a generator expression. All are LAZY and SINGLE-PASS — once exhausted they yield nothing more. PEP 255 is the original generators proposal.
PEP 255 — Simple GeneratorsOpen modes: 'r' read, 'w' TRUNCATES/creates, 'a' appends, 'x' fails if the file exists, '+' read/update, 'b' binary. read()/readline()/readlines() and iterating a file line-by-line. Always prefer `with open(...) as f:` — it closes the file even on an exception (PEP 343).
PEP 343 — The 'with' statementThe LEGB lookup rule, and how a closure (an inner function) captures variables from its enclosing scope. Use `nonlocal` to REBIND an enclosing variable, `global` for module scope. Watch the late-binding trap: closures capture the variable, not its value at creation.
PEP 3104 — Access to Names in Outer ScopesNote: the docs are versioned to Python 3 and match the PCAP-31-03 objectives. Prices/versions of the linked courses shift over time — always confirm the current exam status and syllabus at pythoninstitute.org before you book. The current 31-03 (lifetime validity) is scheduled to retire August 31, 2026.