A language tour
Code that fits in your mind. A language that gets out of the way and lets you think about the problem.
01 โ Readability
Guido van Rossum designed Python to be read as much as it is written. Indentation isn't just style โ it's syntax. The structure of the code mirrors the structure of the thought.
"Readability counts. Special cases aren't special enough to break the rules. If the implementation is hard to explain, it's a bad idea."
โ The Zen of Python (PEP 20), Tim Peters# Python reads close to plain English fruits = ["apple", "banana", "cherry"] if "banana" in fruits: print("We have bananas.") # Chained comparisons โ unlike most languages age = 25 if 18 <= age < 65: print("Working age.") # Ternary that flows like a sentence label = "adult" if age >= 18 else "minor" # Unpacking โ name your data, not your indices first, *rest = fruits print(first) # โ apple print(rest) # โ ['banana', 'cherry']
Chained comparisons like 18 <= age < 65 mirror mathematical notation โ Python trusts you to think naturally.
02 โ Comprehensions
List comprehensions are one of Python's most celebrated features โ a compact syntax for building new collections from existing ones. They eliminate the boilerplate of an append loop while remaining completely readable.
# The long way squares = [] for n in range(10): squares.append(n ** 2) # The Python way โ reads like set-builder notation squares = [n ** 2 for n in range(10)] # Add a condition evens = [n for n in range(20) if n % 2 == 0] # Dict comprehension โ same idea, different brackets words = ["hello", "world", "python"] lengths = {w: len(w) for w in words} # โ {'hello': 5, 'world': 5, 'python': 6} # Generator โ same syntax, lazy evaluation, no memory cost total = sum(n ** 2 for n in range(1_000_000))
The generator expression in the last line sums a million squares without ever holding them all in memory โ lazy by default.
03 โ Decorators
A decorator is just a function that takes a function and returns a new one. But the @ syntax turns this into something that reads like an annotation โ a clear, reusable way to add behaviour without touching the original code.
import time from functools import wraps, cache def timer(func): """Decorator: measure how long a function takes.""" @wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() result = func(*args, **kwargs) end = time.perf_counter() print(f"{func.__name__} took {end - start:.4f}s") return result return wrapper # The @ line reads: "timer-ify this function" @timer def crunch(n): return sum(i * i for i in range(n)) crunch(1_000_000) # โ crunch took 0.0842s # Stack decorators โ they compose @timer @cache def fib(n): if n < 2: return n return fib(n - 1) + fib(n - 2)
Stacking @cache under @timer memoizes the recursive calls โ you compose cross-cutting concerns without touching business logic.
04 โ Context Managers
The with statement is Python's answer to the question: "how do you guarantee cleanup?" It wraps a block with setup and teardown โ and the language guarantees the teardown runs, no matter what happens inside.
# Files โ the classic case with open("data.txt", "r") as f: contents = f.read() # f.close() was called automatically โ even if read() raised # Multiple resources, one line with open("src.txt") as src, open("dst.txt", "w") as dst: dst.write(src.read()) # Build your own with contextlib from contextlib import contextmanager @contextmanager def timer_block(label): start = time.perf_counter() yield # your code runs here elapsed = time.perf_counter() - start print(f"[{label}] {elapsed:.3f}s") with timer_block("matrix multiply"): result = heavy_computation() # โ [matrix multiply] 0.217s
yield inside a @contextmanager splits setup from teardown at a single point โ everything before is enter, everything after is exit.
05 โ Dataclasses & Types
Python's dataclasses generate __init__, __repr__, and __eq__ from a simple field declaration. Pair them with type hints and you get self-documenting, editor-friendly code โ without sacrificing Python's flexibility.
from dataclasses import dataclass, field from typing import ClassVar @dataclass class Album: title: str artist: str year: int tracks: list[str] = field(default_factory=list) genre: ClassVar[str] = "Unknown" def summary(self) -> str: return f"{self.artist} โ {self.title} ({self.year})" # __init__, __repr__, and __eq__ are generated for free album = Album( title = "Kind of Blue", artist = "Miles Davis", year = 1959, tracks = ["So What", "Freddie Freeloader", "Blue in Green"], ) print(album.summary()) # โ Miles Davis โ Kind of Blue (1959) print(album) # โ Album(title='Kind of Blue', artist='Miles Davis', year=1959, ...)
@dataclass turns a class body into a schema โ no hand-written __init__, no repetitive assignment. The field declarations are the documentation.
06 โ The Whole Picture
The standard library covers HTTP, JSON, CSV, dates, regex, compression, cryptography, and more โ before you install a single package.
NumPy, pandas, PyTorch, scikit-learn โ virtually all of modern data science and AI research is written in Python.
enumerate, zip, itertools โ Python's iteration protocol is composable. Generators let you express infinite sequences naturally.
Type hints are optional and progressive. Add them where they help; leave them out where they don't. mypy and editors understand both.
Python ships with an interactive interpreter. Ideas become runnable in seconds. No compile step, no ceremony โ just exploration.
Web backends, CLI tools, automation scripts, notebooks, embedded systems. Python is the duct tape of the modern software world โ and that's a compliment.