๐Ÿ

Python

Python syntax, built-ins, data structures, file I/O, concurrency and tooling

Data Structures

Lists, dicts, sets, tuples and common operations

pythonยทList operations
nums = [3, 1, 4, 1, 5, 9]

nums.append(2)          # add to end
nums.extend([6, 5])     # merge another list
nums.insert(0, 0)       # insert at index
nums.remove(1)          # remove first occurrence
nums.pop()              # remove & return last item
nums.pop(0)             # remove & return at index
nums.sort()             # sort in-place
nums.sort(reverse=True)
sorted_copy = sorted(nums)
nums.reverse()
idx = nums.index(5)     # first index of value
count = nums.count(1)   # occurrences
nums2 = nums[:]         # shallow copy
sliced = nums[1:4]      # slice [start:stop]
sliced = nums[::2]      # every 2nd element
pythonยทDict operations
user = {"name": "Alice", "age": 30}

user["email"] = "alice@example.com"   # add/update
user.get("missing", "default")        # safe get
user.setdefault("role", "user")       # set if absent
user.update({"age": 31, "city": "NY"})
user.pop("city")                      # remove key
"name" in user                        # key existence check

# Iterate
for key, value in user.items(): ...
for key in user.keys(): ...
for value in user.values(): ...

# Merge (Python 3.9+)
merged = user | {"extra": True}

# Dict comprehension
squares = {n: n**2 for n in range(10)}
pythonยทSets
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

a.add(7)
a.discard(99)          # remove if present, no error
a.remove(1)            # remove or raise KeyError

a | b                  # union        {1,2,3,4,5,6}
a & b                  # intersection {3,4}
a - b                  # difference   {1,2}
a ^ b                  # symmetric diff {1,2,5,6}

a.issubset(b)
a.issuperset(b)
a.isdisjoint(b)        # True if no common elements

# Deduplicate a list
unique = list(set([1, 2, 2, 3, 3]))
pythonยทCollections module
from collections import Counter, defaultdict, deque, OrderedDict

# Counter โ€” frequency map
words = ["apple", "banana", "apple", "cherry"]
c = Counter(words)
c.most_common(2)       # [('apple', 2), ('banana', 1)]
c["apple"]             # 2

# defaultdict โ€” no KeyError on missing keys
graph = defaultdict(list)
graph["a"].append("b")

# deque โ€” O(1) append/pop from both ends
dq = deque([1, 2, 3], maxlen=5)
dq.appendleft(0)
dq.popleft()
dq.rotate(1)

# namedtuple
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
p.x, p.y

Comprehensions & Itertools

Concise data transformations and lazy iteration

pythonยทList, dict and set comprehensions
# List comprehension
squares = [x**2 for x in range(10)]
evens   = [x for x in range(20) if x % 2 == 0]

# Nested
matrix = [[1,2,3],[4,5,6]]
flat   = [n for row in matrix for n in row]

# Dict comprehension
inv    = {v: k for k, v in {"a": 1, "b": 2}.items()}

# Set comprehension
unique_lens = {len(w) for w in ["hi", "hello", "hey"]}

# Generator expression (lazy, memory-efficient)
total = sum(x**2 for x in range(1_000_000))
pythonยทitertools essentials
import itertools

# Chaining and slicing
itertools.chain([1,2], [3,4])          # 1 2 3 4
itertools.islice(range(100), 5, 15)    # items 5-14

# Grouping
data = [("a",1),("a",2),("b",3)]
for key, group in itertools.groupby(data, key=lambda x: x[0]):
    print(key, list(group))

# Combinatorics
list(itertools.combinations("ABC", 2))   # [('A','B'),('A','C'),('B','C')]
list(itertools.permutations("AB", 2))    # [('A','B'),('B','A')]
list(itertools.product([0,1], repeat=3)) # all 3-bit combos

# Accumulate
list(itertools.accumulate([1,2,3,4]))    # [1, 3, 6, 10]

# Cycle and repeat
itertools.cycle([1,2,3])       # infinite 1 2 3 1 2 3 ...
itertools.repeat(0, times=5)   # [0, 0, 0, 0, 0]
pythonยทfunctools essentials
from functools import reduce, lru_cache, partial, wraps

# lru_cache โ€” memoize expensive calls
@lru_cache(maxsize=128)
def fib(n):
    return n if n < 2 else fib(n-1) + fib(n-2)

fib.cache_info()   # hits, misses, size

# reduce
total = reduce(lambda acc, x: acc + x, [1,2,3,4], 0)

# partial โ€” pre-fill arguments
from functools import partial
double = partial(pow, exp=2)
double(5)  # 25 (but note: positional only works differently)

add5 = partial(lambda x, y: x + y, 5)
add5(3)    # 8

# wraps โ€” preserve metadata in decorators
def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

Functions & Decorators

Args, kwargs, closures, decorators and type hints

pythonยทArgs, kwargs and keyword-only
def func(pos1, pos2, /, normal, *, kw_only, **kwargs):
    """
    pos1, pos2  โ€” positional-only (before /)
    normal      โ€” positional or keyword
    kw_only     โ€” keyword-only (after *)
    kwargs      โ€” extra keyword arguments
    """
    print(pos1, pos2, normal, kw_only, kwargs)

func(1, 2, "a", kw_only="b", extra=True)

# Unpacking
def add(a, b, c): return a + b + c
args   = [1, 2, 3]
kwargs = {"a": 1, "b": 2, "c": 3}
add(*args)
add(**kwargs)
pythonยทDecorators
import time
from functools import wraps

# Timing decorator
def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__} took {elapsed:.4f}s")
        return result
    return wrapper

# Decorator with arguments
def retry(times=3):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(times):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == times - 1:
                        raise
            return None
        return wrapper
    return decorator

@timer
@retry(times=3)
def fetch_data(url: str) -> dict:
    ...
pythonยทType hints and dataclasses
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Optional

@dataclass
class User:
    name: str
    email: str
    age: int = 0
    tags: list[str] = field(default_factory=list)
    _id: str = field(init=False, repr=False)

    def __post_init__(self):
        self._id = self.email.lower()

    def is_adult(self) -> bool:
        return self.age >= 18

# Frozen (immutable) dataclass
@dataclass(frozen=True)
class Point:
    x: float
    y: float

# Common type hints
def process(
    items: list[int],
    mapping: dict[str, int],
    opt: Optional[str] = None,
) -> tuple[int, ...]:
    ...

OOP & Classes

Classes, inheritance, dunder methods and protocols

pythonยทClass with dunder methods
class Vector:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    def __repr__(self) -> str:
        return f"Vector({self.x}, {self.y})"

    def __str__(self) -> str:
        return f"({self.x}, {self.y})"

    def __add__(self, other: "Vector") -> "Vector":
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, scalar: float) -> "Vector":
        return Vector(self.x * scalar, self.y * scalar)

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Vector):
            return NotImplemented
        return self.x == other.x and self.y == other.y

    def __len__(self) -> int:
        return 2

    def __iter__(self):
        yield self.x
        yield self.y
pythonยทInheritance and super()
class Animal:
    def __init__(self, name: str):
        self.name = name

    def speak(self) -> str:
        raise NotImplementedError

class Dog(Animal):
    def __init__(self, name: str, breed: str):
        super().__init__(name)
        self.breed = breed

    def speak(self) -> str:
        return f"{self.name} says Woof!"

# Multiple inheritance with MRO
class A:
    def method(self): return "A"

class B(A):
    def method(self): return "B -> " + super().method()

class C(A):
    def method(self): return "C -> " + super().method()

class D(B, C):
    pass

D().method()   # "B -> C -> A"
D.__mro__      # MRO resolution order
pythonยทProperties, class and static methods
class Temperature:
    def __init__(self, celsius: float = 0):
        self._celsius = celsius

    @property
    def celsius(self) -> float:
        return self._celsius

    @celsius.setter
    def celsius(self, value: float):
        if value < -273.15:
            raise ValueError("Below absolute zero")
        self._celsius = value

    @property
    def fahrenheit(self) -> float:
        return self._celsius * 9/5 + 32

    @classmethod
    def from_fahrenheit(cls, f: float) -> "Temperature":
        return cls((f - 32) * 5/9)

    @staticmethod
    def absolute_zero() -> float:
        return -273.15

t = Temperature.from_fahrenheit(212)
t.celsius   # 100.0
pythonยทAbstract base classes and protocols
from abc import ABC, abstractmethod
from typing import Protocol, runtime_checkable

# Abstract base class
class Shape(ABC):
    @abstractmethod
    def area(self) -> float: ...

    @abstractmethod
    def perimeter(self) -> float: ...

class Circle(Shape):
    def __init__(self, r: float):
        self.r = r
    def area(self) -> float:
        return 3.14159 * self.r ** 2
    def perimeter(self) -> float:
        return 2 * 3.14159 * self.r

# Protocol (structural subtyping โ€” duck typing with types)
@runtime_checkable
class Drawable(Protocol):
    def draw(self) -> None: ...

class Canvas:
    def draw(self) -> None:
        print("drawing")

isinstance(Canvas(), Drawable)  # True

Error Handling

try/except patterns, custom exceptions and context managers

pythonยทException handling patterns
# Catch specific exceptions
try:
    result = 10 / 0
except ZeroDivisionError as e:
    print(f"Math error: {e}")
except (TypeError, ValueError) as e:
    print(f"Type/Value error: {e}")
except Exception as e:
    raise RuntimeError("Unexpected error") from e
else:
    print("No exception, result:", result)
finally:
    print("Always runs")

# Re-raise with context
try:
    open("missing.txt")
except FileNotFoundError as e:
    raise SystemExit(f"Config file missing: {e}") from e

# Exception groups (Python 3.11+)
try:
    raise ExceptionGroup("multiple", [ValueError("v"), TypeError("t")])
except* ValueError as eg:
    print("Caught ValueErrors:", eg.exceptions)
pythonยทCustom exceptions
class AppError(Exception):
    """Base class for application errors."""

class ValidationError(AppError):
    def __init__(self, field: str, message: str):
        self.field = field
        self.message = message
        super().__init__(f"[{field}] {message}")

class NotFoundError(AppError):
    def __init__(self, resource: str, id: int | str):
        super().__init__(f"{resource} with id={id!r} not found")
        self.resource = resource
        self.id = id

# Usage
try:
    raise ValidationError("email", "must contain @")
except ValidationError as e:
    print(e.field, e.message)
pythonยทContext managers
# Class-based context manager
class Timer:
    def __enter__(self):
        import time
        self.start = time.perf_counter()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.elapsed = time.perf_counter() - self.start
        return False  # don't suppress exceptions

with Timer() as t:
    sum(range(1_000_000))
print(f"Elapsed: {t.elapsed:.4f}s")

# Generator-based with contextlib
from contextlib import contextmanager

@contextmanager
def managed_resource(name: str):
    print(f"Acquiring {name}")
    try:
        yield name
    finally:
        print(f"Releasing {name}")

with managed_resource("db_connection") as res:
    print(f"Using {res}")

# Suppress specific exceptions
from contextlib import suppress
with suppress(FileNotFoundError):
    open("maybe_missing.txt")

File I/O & Paths

Read, write and navigate files with pathlib and built-ins

pythonยทpathlib โ€” modern file paths
from pathlib import Path

p = Path("/etc/app/config.toml")

p.exists()          # True/False
p.is_file()
p.is_dir()
p.suffix            # '.toml'
p.stem              # 'config'
p.name              # 'config.toml'
p.parent            # Path('/etc/app')

# Build paths
base = Path.home() / ".config" / "app"
base.mkdir(parents=True, exist_ok=True)

# Glob
list(Path(".").glob("**/*.py"))
list(Path(".").rglob("*.log"))

# Read / write text
text = p.read_text(encoding="utf-8")
p.write_text("hello", encoding="utf-8")

# Read / write bytes
data = p.read_bytes()
p.write_bytes(b"\x00\x01")

# Iterate directory
for child in Path(".").iterdir():
    print(child.name)
pythonยทReading and writing files
# Read entire file
with open("data.txt", encoding="utf-8") as f:
    content = f.read()

# Read line by line (memory-efficient)
with open("big.log", encoding="utf-8") as f:
    for line in f:
        process(line.rstrip())

# Write / append
with open("out.txt", "w", encoding="utf-8") as f:
    f.write("line one\n")
    f.writelines(["line two\n", "line three\n"])

with open("out.txt", "a") as f:
    f.write("appended\n")

# JSON
import json
with open("data.json") as f:
    data = json.load(f)

with open("out.json", "w") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

# CSV
import csv
with open("data.csv", newline="") as f:
    reader = csv.DictReader(f)
    rows = list(reader)
pythonยทTOML, YAML and environment variables
# TOML (Python 3.11+ built-in)
import tomllib
with open("pyproject.toml", "rb") as f:
    config = tomllib.load(f)

# YAML (pip install pyyaml)
import yaml
with open("config.yml") as f:
    cfg = yaml.safe_load(f)

# Environment variables
import os
from dotenv import load_dotenv   # pip install python-dotenv

load_dotenv()                    # loads .env file

db_url  = os.environ["DATABASE_URL"]          # raises if missing
debug   = os.getenv("DEBUG", "false").lower() == "true"
port    = int(os.getenv("PORT", "8080"))

Concurrency

asyncio, threading, multiprocessing and concurrent.futures

pythonยทasyncio basics
import asyncio
import httpx   # pip install httpx

async def fetch(url: str) -> str:
    async with httpx.AsyncClient() as client:
        resp = await client.get(url)
        return resp.text

async def main():
    urls = [
        "https://api.example.com/1",
        "https://api.example.com/2",
    ]
    # Run concurrently, gather results
    results = await asyncio.gather(*[fetch(u) for u in urls])

    # With error handling
    results = await asyncio.gather(*[fetch(u) for u in urls], return_exceptions=True)

    # Limit concurrency with Semaphore
    sem = asyncio.Semaphore(10)
    async def bounded_fetch(url):
        async with sem:
            return await fetch(url)

    await asyncio.gather(*[bounded_fetch(u) for u in urls])

asyncio.run(main())
pythonยทasync generators and context managers
import asyncio
from contextlib import asynccontextmanager

# Async generator
async def paginate(endpoint: str):
    page = 1
    while True:
        data = await fetch(f"{endpoint}?page={page}")
        if not data:
            break
        yield data
        page += 1

async def collect():
    async for page in paginate("/api/items"):
        process(page)

# Async context manager
@asynccontextmanager
async def db_connection(url: str):
    conn = await connect(url)
    try:
        yield conn
    finally:
        await conn.close()

async def main():
    async with db_connection("postgres://...") as db:
        result = await db.fetch("SELECT 1")
pythonยทconcurrent.futures โ€” threads and processes
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed

# I/O-bound work โ†’ threads
def download(url: str) -> bytes:
    import urllib.request
    with urllib.request.urlopen(url) as r:
        return r.read()

with ThreadPoolExecutor(max_workers=10) as pool:
    futures = {pool.submit(download, url): url for url in urls}
    for future in as_completed(futures):
        url = futures[future]
        try:
            data = future.result()
        except Exception as e:
            print(f"{url} failed: {e}")

# CPU-bound work โ†’ processes
def crunch(n: int) -> int:
    return sum(i**2 for i in range(n))

with ProcessPoolExecutor() as pool:
    results = list(pool.map(crunch, [10**6, 10**6, 10**6]))

Testing with pytest

Fixtures, parametrize, mocking and coverage

bashยทpytest CLI
pytest                          # run all tests
pytest tests/test_user.py       # run single file
pytest -k "auth or login"       # filter by name pattern
pytest -m slow                  # run marked tests
pytest -x                       # stop on first failure
pytest -v                       # verbose output
pytest -s                       # show print statements
pytest --tb=short               # shorter tracebacks
pytest --cov=src --cov-report=html  # coverage report
pythonยทFixtures and parametrize
import pytest

# Fixture
@pytest.fixture
def db_session():
    session = create_test_session()
    yield session
    session.rollback()
    session.close()

# Fixture scopes: function (default), class, module, session
@pytest.fixture(scope="module")
def api_client():
    client = TestClient(app)
    yield client

# Parametrize
@pytest.mark.parametrize("email,valid", [
    ("user@example.com", True),
    ("not-an-email",     False),
    ("",                 False),
    ("a@b.c",            True),
])
def test_email_validation(email: str, valid: bool):
    assert validate_email(email) == valid

# Using fixtures in tests
def test_create_user(db_session):
    user = User(name="Alice", email="alice@example.com")
    db_session.add(user)
    db_session.commit()
    assert user.id is not None
pythonยทMocking with unittest.mock
from unittest.mock import patch, MagicMock, AsyncMock
import pytest

# Patch a function
def test_send_email():
    with patch("myapp.email.smtp_send") as mock_send:
        mock_send.return_value = True
        result = send_welcome_email("user@example.com")
        assert result is True
        mock_send.assert_called_once_with(
            to="user@example.com",
            subject="Welcome!",
        )

# Patch as decorator
@patch("myapp.services.requests.get")
def test_fetch_user(mock_get):
    mock_get.return_value.json.return_value = {"id": 1, "name": "Alice"}
    mock_get.return_value.status_code = 200
    user = fetch_user(1)
    assert user["name"] == "Alice"

# Mock async function
@pytest.mark.asyncio
async def test_async_service():
    with patch("myapp.service.fetch", new_callable=AsyncMock) as mock:
        mock.return_value = {"data": 42}
        result = await process()
        assert result == 42

Tooling & Packaging

uv, pip, venv, pyproject.toml and linting

bashยทuv โ€” fast package manager
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

uv init myproject           # new project with pyproject.toml
uv venv                     # create .venv
uv add requests             # add dependency
uv add pytest --dev         # add dev dependency
uv remove requests          # remove dependency
uv sync                     # install all deps from lockfile
uv run pytest               # run command in project env
uv pip install -r requirements.txt  # install from requirements
uv lock                     # update lockfile
uv tree                     # show dependency tree
bashยทpip & venv
# Create and activate virtual environment
python -m venv .venv
source .venv/bin/activate       # Linux/macOS
.venv\Scripts\activate          # Windows

# Install packages
pip install requests
pip install -r requirements.txt
pip install -e .                # editable install (for dev)

# Freeze and export
pip freeze > requirements.txt
pip list --outdated

# Upgrade packages
pip install --upgrade pip
pip install --upgrade requests

# Uninstall
pip uninstall requests -y
tomlยทpyproject.toml
[project]
name = "myapp"
version = "0.1.0"
description = "My Python application"
requires-python = ">=3.11"
dependencies = [
    "httpx>=0.27",
    "pydantic>=2.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "pytest-asyncio",
    "pytest-cov",
    "ruff",
    "mypy",
]

[project.scripts]
myapp = "myapp.cli:main"

[tool.ruff]
line-length = 88
select = ["E", "F", "I", "UP"]

[tool.mypy]
strict = true
python_version = "3.11"

[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
bashยทruff โ€” fast linter and formatter
# Install
pip install ruff

# Lint
ruff check .                    # check all files
ruff check src/                 # check directory
ruff check --fix .              # auto-fix safe issues

# Format
ruff format .                   # format all files
ruff format --check .           # check without changing

# Common rule sets
# E/W โ€” pycodestyle, F โ€” pyflakes, I โ€” isort
# UP โ€” pyupgrade, B โ€” flake8-bugbear, S โ€” bandit (security)

Useful Built-ins & Snippets

Handy one-liners and patterns that come up constantly

pythonยทString formatting and manipulation
name, age, pi = "Alice", 30, 3.14159

# f-strings (preferred)
f"Hello, {name}! Age: {age}"
f"Pi is approximately {pi:.2f}"
f"{age:05d}"          # zero-padded: 00030
f"{1_000_000:,}"      # thousands sep: 1,000,000
f"{'left':<10}"       # left-align in 10 chars
f"{'right':>10}"      # right-align
f"{name!r}"           # repr: 'Alice'
f"{name!u}"           # not valid โ€” use .upper() instead

# Common methods
"  hello  ".strip()          # 'hello'
"hello world".split()        # ['hello', 'world']
",".join(["a", "b", "c"])    # 'a,b,c'
"hello".startswith("hel")    # True
"HELLO".lower()              # 'hello'
"hello world".title()        # 'Hello World'
"hello".replace("l", "r")   # 'herro'
"abc" * 3                    # 'abcabcabc'
pythonยทUseful built-in functions
# zip and enumerate
names  = ["Alice", "Bob", "Carol"]
scores = [95, 87, 92]

for i, name in enumerate(names, start=1):
    print(f"{i}. {name}")

for name, score in zip(names, scores):
    print(f"{name}: {score}")

# zip_longest (pad shorter iterables)
from itertools import zip_longest
list(zip_longest([1,2,3], [4,5], fillvalue=0))

# map, filter
doubled = list(map(lambda x: x*2, [1,2,3]))
evens   = list(filter(lambda x: x%2==0, range(10)))

# any, all
any(x > 5 for x in [1,3,7,2])  # True
all(x > 0 for x in [1,3,7,2])  # True

# min, max with key
words = ["banana", "apple", "cherry"]
min(words, key=len)            # 'apple'
max(words, key=len)            # 'banana'
sorted(words, key=str.lower)

# vars, dir, type, isinstance
isinstance(42, (int, float))   # True
type(42).__name__              # 'int'
pythonยทDatetime and time
from datetime import datetime, date, timedelta, timezone

now    = datetime.now()
utcnow = datetime.now(tz=timezone.utc)
today  = date.today()

# Format and parse
iso    = now.isoformat()                         # '2025-04-14T12:00:00'
fmt    = now.strftime("%Y-%m-%d %H:%M:%S")
parsed = datetime.strptime("2025-01-15", "%Y-%m-%d")

# Arithmetic
tomorrow   = today + timedelta(days=1)
next_week  = now + timedelta(weeks=1)
diff       = datetime(2025,12,31) - now
diff.days

# Timestamps
ts  = now.timestamp()           # float Unix timestamp
dt  = datetime.fromtimestamp(ts, tz=timezone.utc)

# Comparison
datetime(2025,1,1) < datetime(2025,6,1)   # True
pythonยทWalrus operator, match and other modern syntax
# Walrus operator := (Python 3.8+)
import re
if m := re.search(r"\d+", "abc123def"):
    print(m.group())   # '123'

while chunk := f.read(8192):
    process(chunk)

# Structural pattern matching (Python 3.10+)
command = ("move", 10, 20)

match command:
    case ("quit",):
        quit()
    case ("move", x, y):
        move(x, y)
    case ("say", message) if message:
        print(message)
    case _:
        print("unknown command")

# Match with class patterns
match response:
    case {"status": 200, "data": data}:
        return data
    case {"status": 404}:
        raise NotFoundError()
    case {"status": int(code)}:
        raise HTTPError(code)