Skip to content

Complete Python Programming Study Guide

flowchart TD
    A[Hub] --> B[Key Concepts]
    A --> C[Core Principles]
    A --> D[Practical Applications]
    B --> E[Fundamental definitions]
    C --> F[Design patterns]
    D --> G[Real-world usage]

Python is the most widely used programming language in the world. Its readable syntax, massive ecosystem, and versatility make it the language of choice for data science, web development, automation, education, and scientific computing. But Python’s simplicity is deceptive — the language has deep layers of sophistication that separate competent developers from expert ones.

This hub page maps every resource on this site. The learning path takes you from fundamentals through advanced topics, building a thorough understanding of how Python works under the hood and how to write code that is idiomatic, maintainable, and performant.


Python fundamentals cover the syntax, data types, control flow, and functions that form the foundation of every Python program. Mastering these concepts is essential before moving to more advanced topics.

Dynamic typing means Python determines types at runtime. This makes Python flexible and concise, but it also means type errors surface at runtime rather than compile time. Python 3.12+ supports type hints that allow static type checkers like mypy to catch type errors before execution.

Generators are functions that produce values lazily using the yield keyword. Instead of computing all values at once and storing them in memory, generators compute one value at a time as requested. This makes them ideal for processing large data sets, streaming data, and implementing pipelines.

Decorators are functions that modify other functions. They are commonly used for logging, authentication, caching, and timing. Understanding decorators requires understanding closures — functions that capture variables from their enclosing scope.


Python’s standard library provides powerful built-in data structures. Understanding their internal implementation and performance characteristics is essential for writing efficient code.

Lists are dynamic arrays. They provide O(1) indexed access and O(1) amortised append, but O(n) insertion and deletion in the middle. Use lists when you need ordered, mutable sequences.

Dictionaries are hash tables. They provide O(1) average-case lookup, insertion, and deletion by key. Since Python 3.7, dictionaries preserve insertion order. Use dictionaries for key-value mappings and for counting, grouping, and caching patterns.

Tuples are immutable sequences. They are faster than lists and can be used as dictionary keys (because they are hashable if all elements are hashable). Use tuples for fixed collections of related values.

Sets are unordered collections of unique elements. They provide O(1) membership testing and support set operations (union, intersection, difference, symmetric difference). Use sets for deduplication and membership testing.


Python supports object-oriented programming through classes, inheritance, and protocols. Python’s OOP model differs from statically typed languages — it emphasises duck typing, protocols, and composition over deep inheritance hierarchies.

  • Classes — class definition, init, str, repr, and special methods
  • Metaclasses — type, class creation, and custom metaclasses
  • Descriptorsget, set, delete, and how attributes work under the hood

Duck typing means “if it walks like a duck and quacks like a duck, it is a duck.” Python does not check types — it checks whether an object has the methods and attributes you use. This makes Python extremely flexible but requires clear documentation and testing.

Special methods (also called dunder methods) define how objects behave with Python’s built-in operations. __len__ defines the result of len(), __getitem__ defines indexing with [], and __eq__ defines equality with ==. Implementing these methods makes your classes integrate naturally with Python’s syntax.

Metaclasses control how classes are created. They are rarely needed in application code but are essential for understanding frameworks like Django ORM, SQLAlchemy, and Pydantic. A metaclass intercepts class definition and can modify the class before it is created.


Python’s standard library is one of its greatest strengths. It provides modules for file I/O, networking, concurrency, data serialisation, command-line tools, and more — all without installing third-party packages.

pathlib provides an object-oriented interface to the file system. Instead of manipulating strings with os.path.join, you use Path objects with / operators: path / "subdir" / "file.txt". It is more readable and less error-prone.

itertools provides iterator building blocks — chain, groupby, product, combinations, permutations, and more. These functions enable elegant, memory-efficient data processing pipelines.

functools provides higher-order functions — lru_cache for memoization, partial for partial function application, reduce for cumulative operations, and total_ordering for generating comparison methods.


Python’s async/await syntax enables cooperative multitasking for I/O-bound workloads. Async programming allows a single thread to handle thousands of concurrent connections without the overhead of threading.

  • Async/Await — coroutines, event loops, asyncio, and async patterns

Coroutines are functions defined with async def that can suspend execution and resume later. Unlike threads, coroutines are cooperative — they only suspend at explicit await points, which eliminates data races without locks.

The event loop schedules coroutines and drives I/O operations. When a coroutine awaits an I/O operation, the event loop runs other coroutines while waiting. This enables high concurrency with low overhead.

When to use async: use async for I/O-bound workloads — web servers, database queries, API calls, file downloads. Do not use async for CPU-bound work — use multiprocessing instead. The GIL prevents threads from running Python code in parallel, but coroutines release the GIL during I/O.


Writing correct Python code is not enough — you must write code that is readable, maintainable, and follows community conventions. These practices separate professional Python developers from hobbyists.

PEP 8 is Python’s style guide. It covers naming conventions (snake_case for functions and variables, PascalCase for classes), indentation (4 spaces), line length (79 characters for code, 72 for docstrings), and import ordering. Follow it unless you have a compelling reason not to.

EAFP over LBYL: Python prefers “Easier to Ask Forgiveness than Permission” (try/except) over “Look Before You Leap” (if checks). This is more Pythonic and often more efficient because it avoids redundant checks.

Virtual environments isolate project dependencies. Always use a virtual environment (or conda environment) to avoid dependency conflicts between projects. Tools like venv, poetry, and uv manage environments automatically.


These topics cover Python’s deeper layers — type systems, data validation, context managers, and protocol-based design. They are essential for building robust, production-quality Python applications.

Context managers ensure resources are properly acquired and released. The with statement calls __enter__ on entry and __exit__ on exit, even if an exception is raised. This is Python’s equivalent of C++ RAII.

Pydantic provides data validation using Python type hints. Define a model with types, and Pydantic validates and coerces input data at runtime. It is the standard for data validation in FastAPI, SQLModel, and many other frameworks.

Protocols (PEP 544) enable structural subtyping — a class satisfies a protocol if it has the right methods, regardless of whether it explicitly inherits from the protocol. This is more flexible than nominal subtyping and aligns with Python’s duck-typing philosophy.


Python is broad. Follow this progression to build competence systematically.

  • Learn types, variables, control flow, and functions
  • Understand lists, dictionaries, sets, and tuples
  • Write small programs that read input, process data, and produce output
  • Study object-oriented programming — classes, inheritance, and special methods
  • Learn generators, decorators, and closures
  • Use the standard library for file I/O, serialisation, and CLI tools
  • Master async/await and the asyncio event loop
  • Study type hints and static type checking with mypy
  • Learn Pydantic, context managers, and protocols
  • Study packaging and distribution (pyproject.toml, setuptools)
  • Learn debugging and profiling tools (pdb, cProfile, line_profiler)
  • Write and publish a small Python package

Wyatt’s Notes is a network of interconnected programming and study sites:


Start with the fundamentals — types, control flow, and functions. Write small programs that do something useful: a calculator, a file processor, a simple web scraper. The best way to learn Python is to write Python.

Is Python slow? Should I worry about performance?

Section titled “Is Python slow? Should I worry about performance?”

Python is slower than compiled languages like C++ and Rust, but performance rarely matters for most applications. Profile before optimising — most Python programs are I/O-bound, not CPU-bound. When performance matters, use NumPy, Cython, or write performance-critical sections in C.

The Global Interpreter Lock (GIL) prevents multiple Python threads from executing Python bytecode simultaneously. It means Python threads cannot use multiple CPU cores for CPU-bound work. For CPU-bound work, use multiprocessing. For I/O-bound work, use asyncio or threads (the GIL is released during I/O).

Python 2 reached end-of-life in January 2020. Use Python 3 exclusively. All new code should target Python 3.10 or later.

For web development, learn FastAPI (modern, async, type-hinted) or Django (batteries-included, mature). For data science, learn pandas, NumPy, and matplotlib. For machine learning, learn PyTorch or scikit-learn. Choose based on your domain.

Use a virtual environment for each project. Tools like poetry, uv, or pip-tools manage dependencies and lock versions. Never install packages globally — it leads to dependency conflicts.


Last updated: 24 July 2026

Written by Wyatt. For questions or feedback, visit wyattau.com.