Python

A readable general-purpose language used for scripting, data work, web back ends and teaching.

Status
Complete
Paradigm
object-oriented, imperative, functional
First appeared
1991
Latest version
3.15.0 (October 2026)
Lessons
125

Beginner

Read and write small programs with confidence.

Intermediate

Structure larger programs and use the standard library well.

Object-oriented Python

  1. Classes and objects45 minDefine your own types with class, give each instance its own state through __init__ and self, and tell instance attributes from class attributes.
  2. Properties, class methods and static methods50 minHide internals by convention, expose computed and validated attributes with @property, and choose between instance, class and static methods.
  3. Inheritance and composition55 minReuse code with subclasses and super(), mark intentional overrides with @override, and know when to hold another object instead of inheriting from it.
  4. Defining your own exceptions40 minWrite exception classes that form a family, carry useful data, and chain from the low-level errors they replace.
  5. The Python data model60 minMake your own classes work with print, ==, sorting, len, for loops and operators by implementing the special methods Python calls behind the scenes.
  6. Writing a context manager class45 minBuild your own with-statement support using __enter__ and __exit__, read the exception details in __exit__, and decide whether to swallow an error.
  7. Dataclasses55 minGenerate __init__, __repr__ and __eq__ from a list of annotated fields, then add frozen, slots and keyword-only options as needed.
  8. Enums45 minModel a fixed set of choices with Enum, IntEnum and StrEnum, look members up by name and value, and branch on them with match.
  9. Abstract base classes and protocols50 minDefine what an interface looks like in Python, using duck typing, abstract base classes that refuse incomplete subclasses, and Protocols that checkers verify without inheritance.

Testing, debugging and quality

  1. Automated tests with unittest40 minWrite test cases with the standard library's unittest, run them from the command line, and read what a failing test tells you.
  2. Testing with pytest40 minWrite tests as plain functions with assert, run them with pytest, read its failure reports, and check exceptions with pytest.raises.
  3. Fixtures, parametrization and temporary files45 minShare set-up between pytest tests with fixtures, run one test over many inputs, and isolate files and environment variables with tmp_path and monkeypatch.
  4. A test-driven workflow and a quality gate45 minGrow a function one failing test at a time, measure what your tests miss with coverage, and collect the checks into one command that runs before every commit and in CI.
  5. Mocking with unittest.mock45 minReplace slow, random or external parts of a program with test doubles using Mock, patch and autospec, and check how your code called them.
  6. Docstrings and doctest40 minDocument functions with docstrings that help() and editors can show, and put runnable examples in them so the documentation is tested.
  7. Logging instead of print45 minReplace print statements with the logging module, choose levels, send records to the console and a file, and keep secrets out of the log.
  8. Debugging with pdb45 minGo beyond breakpoint() with conditional breakpoints, post-mortem debugging of crashes, scripted sessions, and attaching pdb to a running process.
  9. Measuring speed with timeit and cProfile40 minTime small snippets with timeit, find the slow function with cProfile, and learn where the 3.15 sampling profiler fits.

Advanced

Typing in depth, advanced data handling, concurrency and metaprogramming.

Typing in depth

  1. Static typing fundamentals55 minType real code precisely with Callable, Literal, Final and TypedDict, know when Any switches checking off, and use cast and reveal_type deliberately.
  2. Generics with type parameter syntax50 min · Python 3.12+Write generic functions, classes and type aliases with the square-bracket syntax from Python 3.12, add bounds, constraints and defaults, and see what the type parameters look like at run time.
  3. Protocols and structural typing50 min · Python 3.12+Type duck-typed code with protocols that describe methods, attributes and call signatures, and write decorators that keep the signature of the function they wrap, with ParamSpec and Concatenate.
  4. Type narrowing45 min · Python 3.13+See how checkers narrow unions through is None, isinstance and equality, write your own narrowing functions with TypeIs and TypeGuard, and make match statements provably exhaustive with assert_never.
  5. Annotations at runtime50 min · Python 3.14+Understand how Python 3.14 stores annotations lazily, read them safely with annotationlib in three formats, resolve them with typing.get_type_hints, and use Annotated metadata to drive a small validator.
  6. TypedDict in depth45 minModel JSON-like data precisely with optional and required keys, read-only keys, typed keyword arguments, and the closed and extra_items options added in Python 3.15.
  7. New in typing (3.15)40 min · Python 3.15+Use the typing features that arrived in Python 3.15, the sentinel builtin, TypeForm and disjoint bases, alongside the slightly older Self and @override that modern code relies on.

Concurrency and parallelism

  1. Concurrency models in Python35 min · Python 3.14+Tell I/O-bound work from CPU-bound work, see what the GIL does and does not stop, and choose between threads, processes, asyncio, interpreters and the free-threaded build.
  2. Threads45 minStart and join threads, see a race condition happen on purpose, fix it with locks, coordinate threads with queues, events, semaphores and conditions, and run I/O-bound jobs with ThreadPoolExecutor.
  3. Processes40 minRun CPU-bound Python on every core with ProcessPoolExecutor, and learn the rules that come with separate processes - the main guard, pickling, copied state and start methods.
  4. asyncio fundamentals45 minWrite coroutines with async def and await, overlap waits with tasks and gather, consume streams with async for and async generators, push blocking calls to a thread with asyncio.to_thread, and run it all with asyncio.run and asyncio.Runner.
  5. Structured concurrency45 minRun many asyncio tasks safely with TaskGroup, feed workers through an asyncio.Queue, put deadlines on them with asyncio.timeout, handle cancellation and grouped errors correctly, and inspect a running program with python -m asyncio ps.
  6. Free-threaded Python40 min · Python 3.14+Install and detect the free-threaded build, run CPU-bound threads in parallel, and learn what changes for thread safety and extension modules when the GIL is gone.
  7. Multiple interpreters40 min · Python 3.14+Create isolated interpreters in one process with concurrent.interpreters, move data between them, and run CPU-bound work in parallel with InterpreterPoolExecutor.

Expert

Performance, CPython internals and production practice, ending with a project that ships a fast tool.

CPython internals

  1. Bytecode and dis45 min · Python 3.12+Read CPython bytecode with dis, take code objects apart, map instructions back to source lines and columns with co_lines() and positions, and watch the specialising interpreter rewrite hot code.
  2. Memory management50 minHow CPython frees objects with reference counting, why some objects are immortal, how the cyclic garbage collector finds what reference counting misses, what happened to the 3.14 incremental collector, and how weak references break cycles.
  3. The GIL and free-threading internals45 min · Python 3.14+What the global interpreter lock actually protects, why removing it needed new reference counting, per-object locks and a new collector design, how extensions declare they are ready, and where PEP 779 leaves the free-threaded build.
  4. The import system45 minFollow an import statement through sys.modules, meta path finders, specs and loaders, write finders and loaders of your own, see how lazy imports defer the search, and replace .pth import lines with .start files.
  5. Monitoring and remote debugging45 min · Python 3.14+Instrument running code with sys.monitoring, build a call counter and a coverage tool that switch themselves off, attach pdb to a live process, run code in another process with sys.remote_exec, and see why 3.15 builds with frame pointers.
  6. A tour of the C API50 min · Python 3.15+Read and write a small CPython extension in C: PyObject pointers, owned and borrowed references, error returns, argument parsing, a method table and the new PyModExport export hook of Python 3.15. Then build it for the stable ABIs abi3 and abi3t.

Production Python

  1. Building and publishing packages50 minTurn a pyproject.toml project into a source distribution and a wheel, read what is inside them, choose version numbers, publish through TestPyPI and trusted publishing, and pin whole environments with the standard pylock.toml lock file.
  2. Command-line applications45 minBuild a command-line tool with argparse subcommands, keep results on stdout and problems on stderr, return meaningful exit codes, run it with python -m or an installed command, and test it in-process.
  3. Secure Python45 minThe Python-specific ways programs get compromised and their fixes: secrets instead of random, password hashing, subprocess without a shell, why pickle runs code, path traversal, TLS verification, untrusted XML and archives, and auditing dependencies.
  4. Configuration and observability55 minRun a Python service in production: typed configuration read once from the environment, logging set up with dictConfig, structured JSON logs with request IDs from a context variable, a tracing sketch, health checks, a clean stop on SIGTERM, and faulthandler for crashes and hangs.
  5. Architecture for large codebases50 minKeep a growing Python application changeable: layers with one-way dependencies, dependency injection through constructors and Protocols, a composition root, boundaries enforced by a checker, typing as documentation, shared state that survives free-threading, monorepos, and lazy imports for start-up time.
  6. Upgrading to Python 3.1555 min · Python 3.15+Plan and carry out an upgrade to Python 3.15: read the porting notes, turn deprecation warnings into errors on the old version, handle the UTF-8 default (PEP 686), the 3.15 removals and behaviour changes, prepare for 3.16 and 3.17, and test across versions, including the free-threaded build.