Lesson 1 — Beginner

Python for AI Engineering

AI engineering ka zyadatar code Python mein hota hai — API clients se lekar data scripts aur test harness tak. Is lesson mein language ki asli taakat aur asli traps dono dekhoge: idiomatic Python, data structures, type hints, mutability, files aur env, async, uv aur pytest — sab ek chhote multi-file project ke nazar se.

⏱ 40 min• Beginner• Basic computer usage

AI engineering mein Python ki kya zarurat padti hai

WHAT

Python ek high-level language hai jiska syntax padhne mein aasaan hai aur standard library rich hai. AI engineering mein iska matlab — data jodna, API call karna, result parse karke aage bhejna, ye sab kam lines mein ho jaata hai.

WHEN

Jab bhi kaam logic + external systems ka ho — API client, data transform, batch script, test harness — Python first choice hai. AI/ML libraries ka ecosystem bhi isi language ka hai.

WHERE

FastAPI services, data pipelines, CLI tools, notebooks aur har dusre AI tool ke wrappers mein Python milega. Is course ke baaki levels ka bhi zyadatar code Python hi hoga.

Funda: Python mein likhna aasaan hai, lekin galat likhna bhi utna hi aasaan. Dynamic typing aur shared references tumhe freedom dete hain — aur wahi freedom se bugs aate hain. Isliye is lesson ka focus sirf syntax nahi, sahi tareeqa hai kaam karna.

Course ka rule: Har snippet ko apne machine pe khud type karke chalao. Copy-paste se debugging nahi seekhti — aur debugging wahi skill hai jo aage har lesson mein kaam aayegi.

Clean, idiomatic Python

from statistics import mean

def grade_students(scores: dict[str, int]) -> dict[str, str]:
    """Har student ko score se grade do."""
    return {name: ("pass" if s >= 40 else "fail") for name, s in scores.items()}


def class_average(scores: dict[str, int]) -> float:
    return mean(scores.values())


class Roster:
    def __init__(self) -> None:
        self.students: dict[str, int] = {}

    def add(self, name: str, score: int) -> None:
        self.students[name] = score

    def __len__(self) -> int:
        return len(self.students)


roster = Roster()
roster.add("Aarti", 78)
print(len(roster), grade_students(roster.students), class_average(roster.students))
Ek line ka style code: Python mein typing karo: Readability counts. Agar code ek line mein nahi padha ja raha, toh naam badlo aur chhota karo — comment se zyada naam bolta hai ki function kyun exist karta hai.

Core data structures — kaunsa kab

# LIST — ordered, mutable (sequence jo badalta rehta hai)
tags = ["rag", "agents", "evals"]
tags.append("fine-tuning")

# TUPLE — ordered, immutable (fixed record)
point = (12, 9)

# SET — unique members, membership O(1) jaisa fast
seen = {"u1", "u2"}
seen.add("u1")
print(len(seen))                # 2 — duplicate gayab

# DICT — key se value dhoondo (lookup ka workhorse)
prices = {"gpu": 40, "cpu": 4}
print(prices.get("tpu", 0))     # missing key pe default, crash nahi

# GENERATOR — lazy sequence, memory bachti hai
def chunks(text: str, size: int):
    for i in range(0, len(text), size):
        yield text[i:i + size]

print(list(chunks("abcdefgh", 3)))   # ["abc", "def", "gh"]
Decision rule: Order + duplicates allowed = list. Har field fixed hai = tuple. Uniqueness/membership = set. Key se dhoondna hai = dict. Sawaal ye nahi "kaunsa common hai" — sawaal hai "iska access pattern kya hai".

Type hints, models aur static analysis

from dataclasses import dataclass
from pydantic import BaseModel, Field, ValidationError

# Type hints — runtime pe rukta nahi, tools isse padh kar galti pakadte hain
def fetch_user(user_id: str, timeout: float = 5.0) -> dict[str, str]: ...

# dataclass — chhota fixed record (init/repr/eq khud ban jaate hain)
@dataclass(frozen=True)
class Token:
    access: str
    expires_in: int

# Pydantic — bahar se aaya data validate karo (API body, JSON, config)
class UserIn(BaseModel):
    name: str = Field(min_length=1)
    email: str
    age: int = Field(default=18, ge=0, le=120)

payload = {"name": "Ravi", "email": "ravi@example.com", "age": -3}
try:
    UserIn.model_validate(payload)
except ValidationError as exc:
    print("validation failed:", exc.errors()[0]["msg"])
Practice: Naye project mein pehle din se type checker on karo (mypy ya pyright) aur ruff se lint bhi. Baad mein types add karna zyada mushkil hota hai — pehle se likhna sasta hai.

Mutability, scope aur common failure modes

def add_tag_galat(tags=[]):          # GALAT — default list sirf ek baar banti hai
    tags.append("new")
    return tags

print(add_tag_galat())               # ["new"]
print(add_tag_galat())               # ["new", "new"] — purana state wapas!

def add_tag(tags: list[str] | None = None):   # SAHI
    tags = tags if tags is not None else []
    tags.append("new")
    return tags

# Reference vs copy — sabse common surprise
counts = [1, 2, 3]
alias = counts             # alag list nahi — wahi object ka doosra naam
alias.append(4)
print(counts)              # [1, 2, 3, 4] — counts bhi badal gaya
snapshot = counts.copy()   # ab alag copy

# Context manager — block chhote hi resource release
with open("app.log", "a") as fh:
    fh.write("boot line")
Yaad rakho: with (context manager) ka rule simple hai — files, locks, connections jo hain unhe hamesha with mein rakho. Exception aane par bhi cleanup hota hai, warna resource leak chup-chaap badhta rehta hai.

Files, paths, environment variables aur JSON

import csv
import json
import os
from pathlib import Path

# Pathlib — OS-agnostic paths (string se mat jodna)
data_dir = Path("data") / "raw"          # data/raw — Windows ho ya Linux
data_dir.mkdir(parents=True, exist_ok=True)

# JSON — dict <-> string (har API response ka format)
report = {"runs": 3, "best_score": 0.91}
(data_dir / "report.json").write_text(json.dumps(report, indent=2))
loaded = json.loads((data_dir / "report.json").read_text())

# CSV — header se fields aate hain
with (data_dir / "runs.csv").open("w", newline="") as fh:
    writer = csv.DictWriter(fh, fieldnames=["run", "score"])
    writer.writeheader()
    writer.writerow({"run": 1, "score": 0.87})

# Environment variables — config code ke bahar
port = int(os.environ.get("PORT", "8000"))
db_url = os.environ["DATABASE_URL"]      # zaroori ho toh missing par clear error
Rule: Code mein sirf logic ho, value nahi. Jo cheez environment badalne par badal sakti hai (URL, port, key, path) wo hamesha env var ya config file se aani chahiye — yehi aage container deployment mein kaam aayega.

Sync vs async — concurrent API calls

import asyncio
import time

import httpx

URLS = [f"https://api.example.com/items/{i}" for i in range(5)]

# SYNC — ek ek karke, har call doosri ka wait karti hai
def fetch_all_sync() -> list:
    with httpx.Client() as client:
        return [client.get(u).json() for u in URLS]

# ASYNC — sab calls lagti hain, wait ek saath hota hai
async def fetch_all_async() -> list:
    async with httpx.AsyncClient() as client:
        tasks = [client.get(u) for u in URLS]
        return [r.json() for r in await asyncio.gather(*tasks)]

async def main() -> None:
    start = time.perf_counter()
    await fetch_all_async()
    print("async done in", round(time.perf_counter() - start, 2), "s")

asyncio.run(main())

Sync ka matlab: ek kaam khatam hone tak baitho. Async ka matlab: ek thread ke andar bahut saare I/O wait ko overlap karo. Network I/O (API calls, DB queries) mein zyadatar waqt wait hota hai — wahi wait async se overlap hota hai. CPU-heavy kaam (image resize, model inference) async se tez nahi hota — uske liye process/thread chahiye.

Decision rule: Script chala kar band karni hai = sync kaafi. Server ke andar ek request ke liye kai external calls = async (agle lesson mein FastAPI ke saath). Pehle sync likh kar measure karo, phir zarurat par async — premature async code padhna mushkil hota hai.

uv, packages aur pytest — project ko pakka banao

# uv — environment + dependency manager (pip + venv + poetry ka kaam)
uv init my-service
uv add fastapi httpx         # dependencies (pyproject + lock update)
uv add --dev pytest ruff     # sirf development ke liye
uv run pytest -q             # environment mein hi test chalao
uv run python -m my_service

# pyproject.toml (uv ne banaya — commit karo)
[project]
name = "my-service"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["fastapi>=0.115", "httpx>=0.27"]

[dependency-groups]
dev = ["pytest>=8", "ruff>=0.6"]

# uv.lock — exact versions + hashes (bhi commit karo)
import pytest

from my_service.grader import grade


def test_pass_boundary():
    assert grade(40) == "pass"


def test_fail_below_boundary():
    assert grade(39) == "fail"


def test_rejects_negative_score():
    with pytest.raises(ValueError):
        grade(-1)

# chalao: uv run pytest -q
Definition of done: Feature tabhi done hai jab uske tests pass ho rahe hain, types check ho rahi hain, aur teammate ka uv sync && uv run pytest tumhare bina chal jaaye. Yehi teen cheezein aage har project mein rahengi.

Exercise

Question: Function ke parameters aur return value ka type batane wala syntax kya kehlata hai? (do shabd)

Question: Do sequences mein se kaunsa immutable hai — list ya tuple?

Question: Python project ke dependencies ka exact version lock karne wala file ka naam? (extension ke saath)

Question: Is lesson mein tests chalane ke liye jo tool use hua uska naam?

Common mistakes

Desi example: Aate ka dabba vs sabzi ki thaila — mutability

Thaila (list) mein jo daalo wo badal sakta hai, aur do logon ki "thaila" ek hi nikli toh dono ka saman aapas mein jud jaata hai. Seal-pack dabba (tuple) khulta hi nahi — isliye fixed record usme rakho:

python
thaila = ["pyaz", "aloo"]
dusri = thaila              # alag thaila nahi — wahi hai
dusri.append("mirch")
print(thaila)               # pyaz, aloo, MIRCH — dono mein mirch aa gayi

dabba = ("namak", "haldi")  # seal-pack
# dabba.append("mirch")     # TypeError — andar kuch badal nahi sakta

# Shared state ho toh copy karo, fixed record ho toh tuple rakho.
Interview angle — yahan se sawaal aate hain
  • Q: list aur tuple ka farq kya hai aur kaunsa kab use karte hain?
  • Q: Type hints runtime pe errors kyun nahi rokte, phir bhi kyun likhte hain? — static analysis (mypy/pyright) ke liye.
  • Q: async/await se performance kis type ke kaam mein badhti hai aur kyun? — I/O wait ko overlap karke.
  • Q: pyproject.toml aur uv.lock ka role kya hai? — declared dependencies vs locked, reproducible environment.
  • Q: Program chalta hai par output galat hai — debugging ka order kya hoga? — traceback, logging, minimal repro.
Lesson complete?

Python ka foundation taiyar. Agla lesson — The Web: HTTP, REST & JSON — mein dekhenge tumhara code internet pe bahar ke systems se kaise baat karta hai.

Popular courses: Data Science Course in Lucknow · AI Course in Lucknow · Python Course in Lucknow · Power BI Course · Data Analytics Course