Important Libraries — Cheat Sheet
Python A–Z · 6 topics. Download the PDF or the Instagram carousel and share it.
requests & httpx — Calling APIs
requests is the de-facto HTTP client: get/post with params and JSON, status checks with raise_for_status, timeouts ALWAYS, and Sessions for connection reuse.
- ✓ALWAYS pass timeout= — the default waits forever and hangs services
- ✓raise_for_status() converts 4xx/5xx into catchable HTTPError
- ✓json= to send, .json() to receive; params= builds query strings safely
- ✓Session = pooling + shared headers + retry mounting; httpx = same API + async
import requests
# GET with query parameters
r = requests.get(
"https://api.github.com/search/repositories",
params={"q": "fastapi", "per_page": 3}, # ?q=fastapi&per_page=3
timeout=10, # ALWAYS set a timeout
)
r.raise_for_status() # raises on 4xx/5xx
data = r.json() # parsed JSON body
print(r.status_code, data["total_count"])
# POST JSON
payload = {"name": "Asha", "plan": "pro"}
r = requests.post(
"https://httpbin.org/post",
json=payload, # serializes + sets header
headers={"Authorization": "Bearer TOKEN"},
timeout=10,
)
print(r.json()["json"]) # {'name': 'Asha', 'plan': 'pro'}
# Error handling that distinguishes failure modes
try:
r = requests.get("https://api.example.com/health", timeout=5)
r.raise_for_status()
except requests.Timeout:
print("service too slow")
except requests.HTTPError as e:
print("bad status:", e.response.status_code)
except requests.ConnectionError:
print("network/DNS problem")Pydantic — Data Validation from Type Hints
Pydantic models validate and convert external data using type annotations — the engine behind FastAPI request validation, with field constraints, custom validators, and clean JSON round-trips.
- ✓Type hints become runtime validation; sensible coercion ("42" → 42), precise errors
- ✓Field(ge=, le=, min_length=...) for constraints; EmailStr and friends for formats
- ✓field_validator for one field, model_validator for cross-field rules
- ✓model_dump()/model_dump_json() serialize; nested models validate whole JSON trees
from pydantic import BaseModel, EmailStr, Field, ValidationError
class SignupRequest(BaseModel):
name: str = Field(min_length=2, max_length=50)
email: EmailStr
age: int = Field(ge=16, le=100)
skills: list[str] = []
referral: str | None = None # optional
ok = SignupRequest(
name="Asha", email="asha@x.com",
age="21", # str -> int, coerced!
skills=["python"],
)
print(ok.age, type(ok.age)) # 21 <class 'int'>
print(ok.model_dump()) # dict
print(ok.model_dump_json()) # JSON string
try:
SignupRequest(name="A", email="not-an-email", age=12)
except ValidationError as e:
for err in e.errors():
print(err["loc"], err["msg"])
# ('name',) String should have at least 2 characters
# ('email',) value is not a valid email address
# ('age',) Input should be greater than or equal to 16SQLAlchemy — Python's Database Toolkit
SQLAlchemy maps classes to tables (ORM), builds queries in Python (select/where/join), and manages transactions with Sessions — the standard DB layer under FastAPI apps.
- ✓Session = unit of work: add/modify objects, commit() writes one transaction
- ✓2.0 style: select(Model).where(...) with session.scalars() — parameterized, injection-safe
- ✓relationship() navigates foreign keys as attributes; back_populates links both sides
- ✓Know the N+1 problem and its fix (selectinload/joinedload) — a favourite interview probe
from sqlalchemy import create_engine, String, select
from sqlalchemy.orm import (DeclarativeBase, Mapped, mapped_column,
Session)
class Base(DeclarativeBase): ...
class Student(Base):
__tablename__ = "students"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
branch: Mapped[str] = mapped_column(String(10))
cgpa: Mapped[float]
engine = create_engine("sqlite:///college.db", echo=False)
Base.metadata.create_all(engine) # CREATE TABLE
with Session(engine) as session:
session.add_all([
Student(name="Asha", branch="CS", cgpa=8.7),
Student(name="Ravi", branch="IT", cgpa=7.9),
])
session.commit() # one transaction
# Query — 2.0 style
stmt = (select(Student)
.where(Student.cgpa >= 8.0) # parameterized — no injection
.order_by(Student.cgpa.desc()))
for s in session.scalars(stmt):
print(s.name, s.cgpa) # Asha 8.7
# Update & delete are just object operations
asha = session.scalar(select(Student).where(Student.name == "Asha"))
asha.cgpa = 9.0
session.commit()pytest — Testing Like a Professional
pytest turns plain assert into a test framework: test_ functions, parametrize for tables of cases, fixtures for setup/teardown, and raises for exception paths.
- ✓Discovery by convention: test_*.py files, test_* functions, plain assert
- ✓pytest.raises(Error, match=...) tests failure paths explicitly
- ✓parametrize = table-driven tests; each row reports separately
- ✓Fixtures inject setup by parameter name; yield fixtures guarantee teardown; conftest.py shares them
# calculator.py
def apply_discount(price, percent):
if not 0 <= percent <= 100:
raise ValueError("percent must be 0-100")
return round(price * (1 - percent / 100), 2)
# test_calculator.py
import pytest
from calculator import apply_discount
def test_basic_discount():
assert apply_discount(1000, 10) == 900.0
def test_zero_percent_returns_price():
assert apply_discount(500, 0) == 500.0
def test_invalid_percent_raises():
with pytest.raises(ValueError, match="0-100"):
apply_discount(1000, 150)
# $ pytest -v
# test_calculator.py::test_basic_discount PASSED
# ...
# On failure, pytest shows values:
# assert apply_discount(1000, 10) == 901
# AssertionError: assert 900.0 == 901NumPy Essentials — Arrays & Vectorization
NumPy arrays store homogeneous data in contiguous memory and operate on whole arrays at C speed — vectorization, broadcasting and boolean masks replace Python loops.
- ✓ndarray = one dtype, contiguous memory — 10-100x faster than list loops
- ✓Vectorize: arr * 2, arr >= 40, arr.mean(axis=...) — loops are a smell in NumPy
- ✓Boolean masks filter and assign: arr[arr < 40] = 40
- ✓Slices are views (share memory); .copy() when you need independence
import numpy as np
marks = np.array([67, 82, 45, 91, 38, 74]) # dtype=int64
# Vectorized ops — whole array at once, C speed
curved = marks + 5 # add to every element
print(curved.mean(), curved.max()) # 71.16... 96
# Boolean masking — filter in one expression
passed = marks[marks >= 40] # array([67, 82, 45, 91, 74])
print((marks >= 40).sum()) # 5 — True counts as 1
marks[marks < 40] = 40 # grace marks, in place!
# 2D — rows = students, cols = subjects
scores = np.array([[80, 90, 70],
[60, 85, 95]])
print(scores.shape) # (2, 3)
print(scores.mean(axis=0)) # per-subject: [70. 87.5 82.5]
print(scores.mean(axis=1)) # per-student: [80. 80.]
# Speed: sum of 10 million squares
big = np.arange(10_000_000)
total = (big ** 2).sum() # ~30x faster than a Python looppandas Essentials — DataFrames for Real Data
pandas DataFrames load, filter, transform and aggregate tabular data — read_csv, boolean filters, groupby/agg, and merge cover the analytics loop every engineer eventually needs.
- ✓DataFrame = table; Series = column; read_csv/to_csv for I/O
- ✓Filter with boolean expressions — & and | with parentheses, never and/or
- ✓groupby().agg() ≈ GROUP BY; merge(on=, how=) ≈ JOIN
- ✓Check df.info() and isna() first — real data always has holes
import pandas as pd
df = pd.DataFrame({
"name": ["Asha", "Ravi", "Neha", "Kiran"],
"branch": ["CS", "IT", "CS", "ME"],
"cgpa": [8.7, 7.2, 9.4, 6.8],
"backlogs": [0, 1, 0, 3],
})
# In real life: df = pd.read_csv("students.csv")
print(df.head()) # first rows
print(df.shape) # (4, 4)
df.info() # dtypes + nulls — ALWAYS check first
# Filtering — & | with parentheses (not and/or!)
eligible = df[(df.cgpa >= 7.0) & (df.backlogs == 0)]
print(eligible.name.tolist()) # ['Asha', 'Neha']
# Derived column
df["grade"] = df.cgpa.apply(lambda c: "A" if c >= 8.5 else "B")
# loc: rows by condition, specific columns
print(df.loc[df.branch == "CS", ["name", "cgpa"]])
# Sort + top-k
print(df.sort_values("cgpa", ascending=False).head(2))