Exploring Python: Language, Control Flow, Data Structures, and More

Table of Contents

Language

Control Flow

# Conditionals
x = 10
if x > 0:
    print("positive")
elif x < 0:
    print("negative")
else:
    print("zero")

# Match statement (Python 3.10+)
match command:
    case "start":
        start_server()
    case "stop":
        stop_server()
    case _:
        print("Unknown command")

# Loops
for i in range(5):
    print(i)

while condition:
    do_something()
    if should_stop:
        break

Data Structures

# Lists
numbers = [1, 2, 3, 4, 5]
numbers.append(6)
squares = [x**2 for x in numbers]

# Dictionaries
person = {"name": "Alice", "age": 30}
person["email"] = "alice@example.com"
names = {p["id"]: p["name"] for p in people}

# Sets
unique = {1, 2, 3, 2, 1}  # {1, 2, 3}
a = {1, 2, 3}
b = {2, 3, 4}
a & b  # intersection: {2, 3}
a | b  # union: {1, 2, 3, 4}

# Tuples (immutable)
point = (3, 4)
x, y = point  # unpacking

Error Handling

try:
    result = risky_operation()
except ValueError as e:
    print(f"Value error: {e}")
except (TypeError, KeyError) as e:
    print(f"Error: {e}")
else:
    print("Success!")
finally:
    cleanup()

# Context managers
with open("file.txt") as f:
    content = f.read()

# Custom exceptions
class ValidationError(Exception):
    pass

Classes

from dataclasses import dataclass
from typing import Optional

# Traditional class
class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

    def greet(self) -> str:
        return f"Hello, I'm {self.name}"

# Dataclass (Python 3.7+)
@dataclass
class User:
    name: str
    email: str
    age: Optional[int] = None

    def is_adult(self) -> bool:
        return self.age is not None and self.age >= 18

Packaging

# pyproject.toml (modern Python packaging)
[project]
name = "mypackage"
version = "0.1.0"
dependencies = [
    "requests>=2.28",
    "pydantic>=2.0",
]

[project.optional-dependencies]
dev = ["pytest", "ruff", "mypy"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Development

Environment

# Using uv (fast Python package installer)
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"

# Or with pip
python -m venv .venv
pip install -e ".[dev]"

Testing

# pytest example
import pytest

def test_addition():
    assert 1 + 1 == 2

@pytest.fixture
def sample_data():
    return {"key": "value"}

def test_with_fixture(sample_data):
    assert sample_data["key"] == "value"

2026 Review

Python in 2026 is a different language from the Python of 2020. Performance improvements, a rethought type system, a transformed tooling ecosystem, and a new role as the lingua franca of the agent era have all compounded. This section documents what changed, what matured, and where the language is heading.

Python 3.13 (October 2024): Free-Threading and JIT

Python 3.13 shipped two headline features, both experimental but production-relevant:

Free-Threaded Mode (PEP 703)

CPython 3.13 introduced a build option (--disable-gil) that removes the Global Interpreter Lock. Python threads can now run truly in parallel on multi-core hardware. The experimental flag PYTHON_GIL=0 enables this at runtime without recompiling.

"""
Demonstrate free-threaded Python 3.13+ with concurrent CPU work.

Run with: PYTHON_GIL=0 python examples/free_threading.py
Requires: Python 3.13+ built with --disable-gil (or 3.13t build)
"""
import sys
import threading
import time

def cpu_bound_task(n: int, results: list[int], index: int) -> None:
    """Compute sum of squares — pure CPU work."""
    total = sum(i * i for i in range(n))
    results[index] = total

def run_threaded(num_threads: int = 4, work_size: int = 1_000_000) -> float:
    results: list[int] = [0] * num_threads
    threads = [
        threading.Thread(target=cpu_bound_task, args=(work_size, results, i))
        for i in range(num_threads)
    ]
    start = time.perf_counter()
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    elapsed = time.perf_counter() - start
    return elapsed

if __name__ == "__main__":
    gil_status = "disabled" if not sys._is_gil_enabled() else "enabled"  # type: ignore[attr-defined]
    print(f"GIL: {gil_status}")
    elapsed = run_threaded()
    print(f"4 threads, 1M work each: {elapsed:.3f}s")

JIT Compiler (PEP 744)

Python 3.13 also shipped a copy-and-patch JIT compiler. It is off by default (PYTHON_JIT=1 to enable) and targets hot inner loops. The specialising adaptive interpreter introduced in 3.11 underpins it.

Python 3.14 (October 2025): Template Strings and Deferred Annotations

Template Strings (PEP 750)

PEP 750 extends f-string syntax with t"..." template literals. Unlike f-strings, template strings return a Template object whose interpolated parts can be inspected before rendering. This makes them safe for SQL, HTML, and shell escaping.

"""
Template strings (PEP 750) — Python 3.14+.

t-strings return a Template object; the caller controls rendering,
enabling safe interpolation into SQL, HTML, or shell commands.
"""
import html as html_mod

# Standard library html module gains t-string support in 3.14
# This example shows the core pattern without stdlib t-string types.

def render_html(template) -> str:
    """Escape interpolated values for safe HTML output."""
    parts: list[str] = []
    for item in template:
        if isinstance(item, str):
            parts.append(item)
        else:
            # item.value is the runtime expression result
            parts.append(html_mod.escape(str(item.value)))
    return "".join(parts)

user_input = "<script>alert('xss')</script>"
# In Python 3.14: template = t"<p>Hello, {user_input}!</p>"
# safe_html = render_html(template)
# => "<p>Hello, &lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;!</p>"
print("Template strings enable safe interpolation — escaping is caller-controlled.")

Deferred Evaluation of Annotations (PEP 649)

PEP 649 replaces PEP 563 (from __future__ import annotations). Annotations are stored as lazy descriptors evaluated only when accessed via __annotations__. This eliminates forward-reference errors without the string-quoting workaround and is faster than eager evaluation.

"""
Deferred annotation evaluation (PEP 649) — Python 3.14+.

Annotations are not evaluated at class/function definition time;
they are computed lazily. Forward references work without quotes.
"""
from __future__ import annotations  # backport shim; native in 3.14

from dataclasses import dataclass

@dataclass
class Node:
    value: int
    # Forward reference — works without quotes under PEP 649
    children: list[Node]

    def depth(self) -> int:
        if not self.children:
            return 0
        return 1 + max(child.depth() for child in self.children)

root = Node(value=1, children=[
    Node(value=2, children=[]),
    Node(value=3, children=[Node(value=4, children=[])]),
])
print(f"Tree depth: {root.depth()}")  # => 2

Python 3.15 Alpha (2026 Preview)

Python 3.15 entered alpha in early 2026. Key proposals under discussion:

  • PEP 768 — Inline comprehension scoping cleanup: comprehension variables no longer leak in edge cases
  • PEP 779asyncio.TaskGroup improvements for structured concurrency, aligning with Trio semantics
  • Immortal objects (PEP 683 follow-on) — extended to more built-in types, reducing reference-count churn
  • sys.monitoring stabilisation — the low-overhead tracing API (3.12) reaches stable ABI in 3.15

Typing Ecosystem Matured

The typing story that began with PEP 484 (3.5, 2015) reached a stable, practical equilibrium in 2025–2026.

Feature PEP Since Status
TypedDict 589 3.8 Stable; NotRequired, ReadOnly added
ParamSpec 612 3.10 Widely adopted for decorator typing
TypeVarTuple 646 3.11 Variadic generics for *args typing
TypeVar defaults 696 3.13 Simplifies generic class defaults
@override 698 3.12 Explicit subclass method override marker
type statement 695 3.12 type Vector = list[float] replaces TypeAlias

Static analysis is now split between two tools: mypy (pioneer, broad ecosystem support) and pyright (faster, strict, powers Pylance in VS Code). Most teams run both in CI.

Tooling: uv and ruff Replace the Stack

Astral shipped uv (Rust-based Python installer and resolver) and ruff (Rust-based linter and formatter) in 2023–2024. By 2026 they have effectively replaced the previous standard stack:

Old tool Replacement Speed gain
pip + pip-tools uv pip / uv sync 10--100x
poetry uv (project management) 10x
virtualenv uv venv 80x
flake8 ruff check 100x
black ruff format 30x
isort ruff check --select I included

uv reads the same pyproject.toml as poetry; migration is largely mechanical. The lockfile (uv.lock) is cross-platform and reproducible.

diagram-python-ecosystem.png

Python in the Agent Era

Python became the default language for AI agent development in 2024–2026, driven by three converging forces: the Anthropic and OpenAI SDKs shipping Pythonic APIs first, the MCP (Model Context Protocol) SDK targeting Python as its reference implementation, and the pydantic library becoming the canonical interface for structured LLM output.

MCP SDK

The MCP Python SDK provides the reference server and client implementations. An MCP server exposes tools, resources, and prompts over a JSON-RPC transport:

from mcp.server import FastMCP

mcp = FastMCP("my-tool-server")

@mcp.tool()
def search(query: str, limit: int = 10) -> list[dict]:
    """Full-text search over the knowledge base."""
    return perform_search(query, limit)

if __name__ == "__main__":
    mcp.run()  # stdio transport by default

Structured Output with Pydantic

Both the Anthropic and OpenAI SDKs accept Pydantic models directly for structured output:

from anthropic import Anthropic
from pydantic import BaseModel

class CodeReview(BaseModel):
    summary: str
    issues: list[str]
    severity: str  # "low" | "medium" | "high"
    approved: bool

client = Anthropic()
response = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Review this diff: ..."}],
)
# Structured parsing with tool_use or beta structured output

Key Libraries (2026)

Library Purpose Notes
anthropic Claude API client Streaming, tooluse, vision
openai OpenAI API client Compatible with many providers
mcp MCP server/client FastMCP high-level API
pydantic v2 Validation + serialization Rust core, 5–50x faster than v1
httpx Async HTTP Replaces requests in async contexts
rich Terminal output Progress, tables, syntax highlight
typer CLI framework Built on click + type hints

Resources

Author: Jason Walsh

j@wal.sh

Last Updated: 2026-04-19 08:29:49

build: 2026-04-20 23:43 | sha: d110973