Skip to content

Split View: Python 완전 가이드 — FastAPI·AsyncIO·Pydantic·uv·Polars·AI 엔지니어링 (Season 2 Ep 5, 2025)

|

Python 완전 가이드 — FastAPI·AsyncIO·Pydantic·uv·Polars·AI 엔지니어링 (Season 2 Ep 5, 2025)

들어가며 — 2025년의 Python은 2015년의 Python이 아니다

Python을 10년 전 배우고 지금 돌아온 사람이 가장 놀랄 변화들:

  • uv (2024): pip·poetry·pyenv·pip-tools를 모두 대체하는 Rust 작성 통합 도구. 10~100배 빠름
  • Pydantic v2 (2023): 검증 엔진을 Rust로 재작성. 5~50배 빠름
  • FastAPI: 타입 힌트 기반 API 프레임워크의 사실상 표준
  • Polars (2024~): Pandas 대체. Rust 기반, 10~100배 빠름, 메모리 효율
  • Python 3.13 (2024/10): Free-threading(No-GIL) 실험, JIT 컴파일러, 개선된 인터랙티브 쉘
  • LangChain·LangGraph·Pydantic AI (2024~): AI 에이전트 스택
  • Ruff + mypy / pyright: Lint·Format·타입체크 모두 빠른 도구로 교체

Python은 "AI 엔지니어링의 공용어"로 확고히 자리잡았고, 도구 체인 전체가 Rust로 재작성되며 속도 문제도 해결되고 있다.


1부 — Python 3.13: 언어의 미래

1.1 Free-threading (No-GIL) — PEP 703

30년 된 GIL(Global Interpreter Lock)을 제거하는 Experimental Build 등장 (2024/10):

python3.13t # free-threaded build
  • GIL: 한 번에 1개 스레드만 Python 바이트코드 실행
  • No-GIL: 진정한 멀티코어 병렬성

한계: 현재 실험적, 단일 스레드 성능 10% 하락, C 확장 호환성 이슈. 20262027년 안정화 예상.

1.2 JIT Compiler — PEP 744

Copy-and-Patch JIT 추가 (실험):

python --enable-experimental-jit

초기 벤치마크는 미미(~5%)지만 장기적으로 PyPy 수준의 성능 가능성.

1.3 개선된 REPL

3.13의 표준 REPL이 드디어 사용 가능:

  • 멀티라인 편집
  • 구문 하이라이팅
  • 페이스트 모드
  • 블록 히스토리

PyPy·ipython에 의존했던 것들이 기본으로.

1.4 Type System 개선 (3.12~3.13)

# PEP 695: Generic Syntax
def first[T](items: list[T]) -> T:
    return items[0]

class Stack[T]:
    def __init__(self) -> None:
        self.items: list[T] = []

# PEP 696: Type Parameter Defaults
def process[T = str](x: T) -> T: ...

# PEP 742: TypeIs
from typing import TypeIs
def is_str(x: object) -> TypeIs[str]:
    return isinstance(x, str)

2부 — uv: 패키지 매니저 혁명

2.1 왜 uv가 게임 체인저인가

Astral이 만든 Rust 기반 통합 도구 (Ruff 제작사). 대체 대상:

  • pip → 설치
  • pip-tools → 해시 pinned requirements
  • pyenv → 파이썬 버전 관리
  • virtualenv/venv → 가상환경
  • poetry → 프로젝트 관리
  • pipx → CLI 도구 설치

속도: pip install이 10초 걸리는 프로젝트가 uv로는 0.1초.

2.2 기본 사용법

# 설치
curl -LsSf https://astral.sh/uv/install.sh | sh

# 프로젝트 초기화
uv init my-app
cd my-app

# 의존성 추가 (pyproject.toml 자동 업데이트)
uv add fastapi uvicorn
uv add --dev pytest ruff mypy

# 실행
uv run python main.py
uv run pytest

# Python 버전 관리
uv python install 3.13
uv python pin 3.13

# Lock 파일 (uv.lock)
uv lock
uv sync

2.3 uv script (단일 파일 Python)

# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "httpx",
#     "rich",
# ]
# ///

import httpx
from rich import print

print(httpx.get("https://api.github.com").json())
uv run script.py
# 의존성 자동 다운로드 후 실행

2025년 새 프로젝트는 uv로 시작하는 것이 표준.


3부 — Pydantic v2: 타입 기반 검증

3.1 v2의 혁명

  • Rust로 재작성된 pydantic-core
  • 5~50배 빠름
  • Annotated 기반 강력한 제약
  • Serialization API 분리

3.2 기본 사용

from pydantic import BaseModel, EmailStr, Field
from typing import Annotated
from datetime import datetime

class User(BaseModel):
    id: int
    email: EmailStr
    name: Annotated[str, Field(min_length=1, max_length=100)]
    age: Annotated[int, Field(ge=0, le=150)]
    created_at: datetime

# 검증 + 변환
user = User.model_validate({
    "id": 1,
    "email": "alice@example.com",
    "name": "Alice",
    "age": 30,
    "created_at": "2025-01-01T00:00:00Z"
})

# 직렬화
json_str = user.model_dump_json()
dict_data = user.model_dump()

3.3 고급 기능

from pydantic import field_validator, model_validator

class Post(BaseModel):
    title: str
    content: str
    tags: list[str] = []

    @field_validator('title')
    @classmethod
    def title_not_empty(cls, v: str) -> str:
        if not v.strip():
            raise ValueError('title cannot be empty')
        return v.strip()

    @model_validator(mode='after')
    def check_tags_limit(self) -> 'Post':
        if len(self.tags) > 10:
            raise ValueError('too many tags')
        return self

3.4 Pydantic Settings

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str
    api_key: str
    debug: bool = False

    class Config:
        env_file = ".env"

settings = Settings()

환경변수·config 관리의 표준.


4부 — FastAPI: 타입 안전 API 표준

4.1 기본 예제

from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel

app = FastAPI()

class UserCreate(BaseModel):
    email: str
    password: str

class UserResponse(BaseModel):
    id: int
    email: str

@app.post("/users", response_model=UserResponse)
async def create_user(user: UserCreate) -> UserResponse:
    # user는 이미 검증됨
    # 응답은 UserResponse로 자동 직렬화
    return UserResponse(id=1, email=user.email)
  • Pydantic 모델이 요청·응답 스키마
  • OpenAPI 자동 생성 (/docs)
  • Dependency Injection 내장

4.2 Dependency Injection

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        yield session

async def get_current_user(token: str = Header(...)) -> User:
    # 토큰 검증 로직
    return user

@app.get("/me")
async def me(user: User = Depends(get_current_user)) -> UserResponse:
    return user

4.3 2025년 FastAPI 스택

목적라이브러리
WebFastAPI
ORMSQLAlchemy 2.0 (async), SQLModel
DB 드라이버asyncpg (Postgres), motor (Mongo)
MigrationAlembic
Dramatiq, Celery 5.x, Taskiq
캐시Redis + aioredis
테스트pytest + httpx
관측성OpenTelemetry + Prometheus

5부 — AsyncIO 실전

5.1 기본 구조

import asyncio

async def fetch(url: str) -> str:
    # 시뮬레이션
    await asyncio.sleep(1)
    return f"data from {url}"

async def main() -> None:
    # 순차
    r1 = await fetch("a")
    r2 = await fetch("b")

    # 동시 (2배 빠름)
    r1, r2 = await asyncio.gather(fetch("a"), fetch("b"))

asyncio.run(main())

5.2 TaskGroup (Python 3.11+)

async def main():
    async with asyncio.TaskGroup() as tg:
        t1 = tg.create_task(fetch("a"))
        t2 = tg.create_task(fetch("b"))
        t3 = tg.create_task(fetch("c"))
    # 컨텍스트 나오면 모든 task 완료
    # 하나라도 예외면 나머지 취소 + ExceptionGroup
    print(t1.result(), t2.result(), t3.result())

TaskGroup이 asyncio.gather보다 낫다: 구조적 동시성, 자동 취소, 명확한 에러.

5.3 asyncio.timeout (Python 3.11+)

async def fetch_with_timeout():
    async with asyncio.timeout(5.0):
        return await slow_operation()

5.4 AsyncIO 함정 5가지

  1. 블로킹 코드 혼합: requests.get 대신 httpx.AsyncClient
  2. asyncio.run 중첩: 이벤트 루프 충돌. nest_asyncio는 아티 패턴
  3. task 참조 유지 실패: asyncio.create_task 결과를 어딘가 저장해야 GC 안됨
  4. CPU 바운드 작업: run_in_executor로 별도 스레드/프로세스
  5. async def 안에서 time.sleep: asyncio.sleep 써야

6부 — Polars: Pandas의 2025년 대체재

6.1 왜 Polars인가

항목PandasPolars
엔진NumPy (C)Rust + Arrow
속도기준5~100배 빠름
메모리많이 씀Pandas의 ~50%
병렬성거의 없음자동 다중 스레드
Lazy 실행✅ (옵티마이저)
대규모 데이터어려움스트리밍 가능

6.2 기본 사용

import polars as pl

df = pl.read_csv("data.csv")

result = (
    df
    .filter(pl.col("age") > 30)
    .group_by("country")
    .agg([
        pl.col("salary").mean().alias("avg_salary"),
        pl.col("id").count().alias("count"),
    ])
    .sort("avg_salary", descending=True)
)

6.3 Lazy Evaluation

lazy_df = pl.scan_csv("huge.csv")  # 실제 읽지 않음

result = (
    lazy_df
    .filter(pl.col("year") == 2024)
    .group_by("category")
    .agg(pl.col("amount").sum())
    .collect()  # 이제 실행 (옵티마이저가 계획 수립)
)

쿼리 옵티마이저가 SQL DBMS처럼 실행 계획을 최적화.

6.4 2025년 전환 가이드

  • 새 프로젝트: Polars 기본값
  • 기존 Pandas 프로젝트: 점진 전환 (df.to_pandas() 브릿지)
  • 시각화는 여전히 Pandas가 편할 수 있음 (matplotlib/seaborn)
  • ML 라이브러리 호환은 아직 Pandas 우세 (개선 중)

7부 — AI 엔지니어링 스택 2025

7.1 LangChain의 현재

LangChain은 2023년 폭발, 2024년 성장통, 2025년 LangGraph 중심으로 재편.

  • LangChain Core: 기본 추상화 (Runnable)
  • LangGraph: 상태 기반 에이전트 그래프 (2025년 표준)
  • LangSmith: 관측성·평가

7.2 LangGraph 예제

from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI

class State(TypedDict):
    messages: Annotated[list, operator.add]

def agent(state: State):
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

def should_continue(state: State) -> str:
    last = state["messages"][-1]
    if last.tool_calls:
        return "tools"
    return END

workflow = StateGraph(State)
workflow.add_node("agent", agent)
workflow.add_node("tools", tool_node)
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue)
workflow.add_edge("tools", "agent")

app = workflow.compile()

Directed Graph + 상태 머신 모델. 복잡한 에이전트 흐름에 이상적.

7.3 Pydantic AI (2024~)

Pydantic 팀이 만든 타입 안전 에이전트 프레임워크. 경량·직관적.

from pydantic_ai import Agent
from pydantic import BaseModel

class WeatherResponse(BaseModel):
    city: str
    temp_c: float
    condition: str

agent = Agent(
    'openai:gpt-4o',
    result_type=WeatherResponse,
    system_prompt='You are a weather assistant.',
)

result = await agent.run('Weather in Seoul?')
print(result.data)  # WeatherResponse 타입

7.4 2025년 AI 스택 추천

상황추천
복잡한 멀티스텝 에이전트LangGraph
간단한 타입 안전 에이전트Pydantic AI
RAG 특화LlamaIndex
프로덕션 최소 의존성OpenAI SDK 직접
TS 팀과 협업Vercel AI SDK (TS) 매치

8부 — Modern Python 개발 환경

8.1 도구 체인 (2025 표준)

# pyproject.toml
[project]
name = "my-app"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.115",
    "pydantic>=2.9",
    "uvicorn>=0.30",
]

[dependency-groups]
dev = [
    "pytest>=8",
    "ruff>=0.7",
    "mypy>=1.13",
]

[tool.ruff]
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP", "B", "S", "C4", "PL"]

[tool.mypy]
strict = true

8.2 Ruff — 10~100배 빠른 린터/포매터

  • Flake8, Black, isort, pyupgrade, pylint 대체
  • Rust 작성
  • 800+ 규칙 내장

8.3 타입 체커 선택

도구특징
mypy가장 오래됨, 느림, 보수적
pyrightMS 제작, 빠름, 엄격
pyreMeta 제작, 서버 모드
tyAstral 제작 (2025), Rust 기반 (개발 중)

2025년 추천: 신규는 pyright, 기존은 mypy 유지. ty 출시 기다리는 중.

8.4 테스트

# pytest + httpx for FastAPI
import pytest
from httpx import AsyncClient, ASGITransport
from myapp.main import app

@pytest.mark.asyncio
async def test_create_user():
    async with AsyncClient(
        transport=ASGITransport(app=app), base_url="http://test"
    ) as ac:
        r = await ac.post("/users", json={"email": "a@b.com", "password": "pw"})
        assert r.status_code == 200

9부 — Python이 빛나는 분야 vs 빛나지 않는 분야

9.1 빛남

  • AI/ML: PyTorch, JAX, scikit-learn, Hugging Face
  • 데이터 엔지니어링: Airflow, dbt, Dagster
  • API 서버: FastAPI의 생산성
  • 과학 컴퓨팅: NumPy, SciPy
  • 스크립팅/자동화: 글루 언어
  • 교육: 학습 곡선 낮음

9.2 빛나지 않음

  • CPU 바운드 고성능: Rust/Go/C++
  • 모바일 앱: Swift/Kotlin
  • 임베디드: C/Rust
  • 게임 엔진: C++
  • 브라우저: JS/TS (Pyodide는 특수 용도)

2025년 현실: Python은 "AI·데이터·API"의 표준이지만, "모든 것을 위한" 언어는 아니다.


10부 — Python 마스터 로드맵 6개월

Month 1: 3.13 기본기

  • 타입 힌트 완전 이해 (PEP 695, Union, Literal, Protocol)
  • uv로 프로젝트 관리
  • Ruff + mypy/pyright 설정

Month 2: Pydantic + FastAPI

  • Pydantic v2 심화 (Annotated, Validators)
  • FastAPI 실전 API 만들기
  • Dependency Injection 패턴

Month 3: AsyncIO

  • TaskGroup, asyncio.timeout
  • httpx·asyncpg 비동기 DB
  • 동시성 제한 (Semaphore)

Month 4: 데이터 처리

  • Polars 마스터
  • SQL + SQLAlchemy 2.0 async
  • DuckDB + Parquet

Month 5: AI 엔지니어링

  • OpenAI/Anthropic SDK
  • LangGraph 또는 Pydantic AI
  • Vector DB (Qdrant, Pinecone, pgvector)
  • RAG 파이프라인 구축

Month 6: 운영

  • Docker + Kubernetes 배포
  • 관측성 (OpenTelemetry, Prometheus)
  • CI/CD (GitHub Actions)
  • 프로파일링 (py-spy, scalene)

11부 — Python 체크리스트 12

  1. uv의 4가지 대체 도구(pip/poetry/pyenv/pip-tools)를 안다
  2. Pydantic v1 vs v2 주요 변화를 안다
  3. FastAPI Dependency Injection 사용법을 안다
  4. TaskGroup vs asyncio.gather 차이를 안다
  5. Polars Lazy Evaluation의 장점을 안다
  6. 타입 힌트 Protocol, TypeIs 사용법을 안다
  7. SQLAlchemy 2.0 async 스타일을 안다
  8. GIL과 Free-threading의 의미를 안다
  9. LangGraph와 LangChain의 관계를 안다
  10. Ruff가 대체하는 도구들을 안다
  11. Pydantic Settings로 설정 관리를 할 수 있다
  12. pytest + httpx로 async API 테스트를 쓸 수 있다

12부 — Python 안티패턴 10

  1. pip install + requirements.txt만 사용: 재현성 취약. uv + uv.lock
  2. 타입 힌트 없이 Python 코드 작성: mypy/pyright로 잡힐 버그 방치
  3. from X import *: 네임스페이스 오염
  4. print()로 디버깅: logging 또는 rich
  5. except Exception: pass: 조용히 실패. 구체 예외 + 로깅
  6. 뮤터블 기본 인자: def f(x=[]): → 공유됨. x=Nonex or []
  7. Pandas에서 iterrows: 느림. 벡터 연산 또는 Polars
  8. Sync 라이브러리를 async 함수에서: 이벤트 루프 블록
  9. os.path 대신 pathlib를 안 씀: pathlib 훨씬 깔끔
  10. 도커 이미지에 pip install -r requirements.txt: layer caching 망침. uv sync --frozen

마치며 — Python은 AI 시대에 다시 태어났다

Python의 원래 강점은 "생산성과 학습 곡선"이었다. 단점은 "속도와 동시성"이었다.

2024~2025년:

  • 속도: uv·Pydantic·Polars·Ruff가 Rust 엔진으로 해결
  • 동시성: Free-threading 실험, AsyncIO 성숙
  • 타입: 3.12~3.13의 PEP들로 강력해짐
  • 생태계: AI 엔지니어링의 표준 언어

"Python이 느리다"는 2020년까지의 이야기였다. 2025년 Python은 **"AI 시대의 공용어이자, Rust 도구들로 빨라진 언어"**다.

시니어 엔지니어가 Python을 안 다룰 수 없는 이유는 명확하다. AI·데이터·API·스크립팅에서 Python은 여전히, 그리고 앞으로도 지배적이다.


다음 글 예고 — "LLM 완전 가이드: Transformer·Attention·RLHF·RAG·Agent·Evaluation"

Season 2 Ep 6은 2025년 엔지니어의 교양, LLM의 내부 구조. 다음 글은:

  • Transformer가 실제로 어떻게 동작하는가
  • Attention 메커니즘 수식까지
  • Pre-training → SFT → RLHF → DPO 흐름
  • RAG의 3세대 진화 (Naive → Advanced → Agentic)
  • Agent 설계 (ReAct, Plan-and-Execute, Multi-Agent)
  • LLM 평가의 진짜 어려움 (LM-as-a-Judge의 한계)

블랙박스를 뜯어보는 시간, 다음 글에서 이어진다.

Python Complete Guide — FastAPI, AsyncIO, Pydantic, uv, Polars, AI Engineering (Season 2 Ep 5, 2025)

Intro — 2025 Python is not 2015 Python

If you learned Python 10 years ago and came back today, the biggest changes:

  • uv (2024): a Rust-written unified tool replacing pip, poetry, pyenv, pip-tools. 10-100x faster
  • Pydantic v2 (2023): validation engine rewritten in Rust. 5-50x faster
  • FastAPI: the de facto standard for type-hint-based API frameworks
  • Polars (2024+): Pandas replacement. Rust-based, 10-100x faster, memory efficient
  • Python 3.13 (2024/10): Free-threading (No-GIL) experiment, JIT compiler, improved REPL
  • LangChain, LangGraph, Pydantic AI (2024+): AI agent stack
  • Ruff + mypy/pyright: Lint, Format, type check — all replaced with fast tooling

Python has firmly settled as "the lingua franca of AI engineering," and the entire toolchain is being rewritten in Rust, closing the speed gap.


Part 1 — Python 3.13: the future of the language

1.1 Free-threading (No-GIL) — PEP 703

An Experimental Build removing the 30-year-old GIL (Global Interpreter Lock), released 2024/10:

python3.13t # free-threaded build
  • GIL: only one thread executes Python bytecode at a time
  • No-GIL: true multi-core parallelism

Limits: currently experimental, ~10% single-thread regression, C extension compatibility issues. Expected to stabilize 2026-2027.

1.2 JIT Compiler — PEP 744

Copy-and-Patch JIT added (experimental):

python --enable-experimental-jit

Initial benchmarks modest (~5%), but long-term potential for PyPy-level performance.

1.3 Improved REPL

The standard REPL in 3.13 is finally usable:

  • Multi-line editing
  • Syntax highlighting
  • Paste mode
  • Block history

The things you used PyPy/ipython for, now built in.

1.4 Type System improvements (3.12-3.13)

# PEP 695: Generic Syntax
def first[T](items: list[T]) -> T:
    return items[0]

class Stack[T]:
    def __init__(self) -> None:
        self.items: list[T] = []

# PEP 696: Type Parameter Defaults
def process[T = str](x: T) -> T: ...

# PEP 742: TypeIs
from typing import TypeIs
def is_str(x: object) -> TypeIs[str]:
    return isinstance(x, str)

Part 2 — uv: the package manager revolution

2.1 Why uv is a game changer

Rust-based unified tool by Astral (makers of Ruff). Replaces:

  • pip → install
  • pip-tools → hash-pinned requirements
  • pyenv → Python version management
  • virtualenv/venv → virtual environments
  • poetry → project management
  • pipx → CLI tool installation

Speed: a pip install that takes 10 seconds runs in 0.1 seconds with uv.

2.2 Basic usage

# install
curl -LsSf https://astral.sh/uv/install.sh | sh

# initialize project
uv init my-app
cd my-app

# add dependencies (pyproject.toml auto-updated)
uv add fastapi uvicorn
uv add --dev pytest ruff mypy

# run
uv run python main.py
uv run pytest

# Python version management
uv python install 3.13
uv python pin 3.13

# lock file (uv.lock)
uv lock
uv sync

2.3 uv script (single-file Python)

# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "httpx",
#     "rich",
# ]
# ///

import httpx
from rich import print

print(httpx.get("https://api.github.com").json())
uv run script.py
# dependencies auto-downloaded, then run

Starting new projects with uv is the 2025 standard.


Part 3 — Pydantic v2: type-based validation

3.1 The v2 revolution

  • pydantic-core rewritten in Rust
  • 5-50x faster
  • Strong constraints via Annotated
  • Separated serialization API

3.2 Basic usage

from pydantic import BaseModel, EmailStr, Field
from typing import Annotated
from datetime import datetime

class User(BaseModel):
    id: int
    email: EmailStr
    name: Annotated[str, Field(min_length=1, max_length=100)]
    age: Annotated[int, Field(ge=0, le=150)]
    created_at: datetime

# validate + convert
user = User.model_validate({
    "id": 1,
    "email": "alice@example.com",
    "name": "Alice",
    "age": 30,
    "created_at": "2025-01-01T00:00:00Z"
})

# serialize
json_str = user.model_dump_json()
dict_data = user.model_dump()

3.3 Advanced features

from pydantic import field_validator, model_validator

class Post(BaseModel):
    title: str
    content: str
    tags: list[str] = []

    @field_validator('title')
    @classmethod
    def title_not_empty(cls, v: str) -> str:
        if not v.strip():
            raise ValueError('title cannot be empty')
        return v.strip()

    @model_validator(mode='after')
    def check_tags_limit(self) -> 'Post':
        if len(self.tags) > 10:
            raise ValueError('too many tags')
        return self

3.4 Pydantic Settings

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str
    api_key: str
    debug: bool = False

    class Config:
        env_file = ".env"

settings = Settings()

The standard for env vars and config management.


Part 4 — FastAPI: the type-safe API standard

4.1 Basic example

from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel

app = FastAPI()

class UserCreate(BaseModel):
    email: str
    password: str

class UserResponse(BaseModel):
    id: int
    email: str

@app.post("/users", response_model=UserResponse)
async def create_user(user: UserCreate) -> UserResponse:
    # user is already validated
    # response auto-serialized as UserResponse
    return UserResponse(id=1, email=user.email)
  • Pydantic models are the request/response schemas
  • OpenAPI auto-generated (/docs)
  • Dependency Injection built-in

4.2 Dependency Injection

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        yield session

async def get_current_user(token: str = Header(...)) -> User:
    # token validation logic
    return user

@app.get("/me")
async def me(user: User = Depends(get_current_user)) -> UserResponse:
    return user

4.3 2025 FastAPI stack

PurposeLibrary
WebFastAPI
ORMSQLAlchemy 2.0 (async), SQLModel
DB driverasyncpg (Postgres), motor (Mongo)
MigrationAlembic
QueueDramatiq, Celery 5.x, Taskiq
CacheRedis + aioredis
Testpytest + httpx
ObservabilityOpenTelemetry + Prometheus

Part 5 — AsyncIO in practice

5.1 Basic structure

import asyncio

async def fetch(url: str) -> str:
    # simulation
    await asyncio.sleep(1)
    return f"data from {url}"

async def main() -> None:
    # sequential
    r1 = await fetch("a")
    r2 = await fetch("b")

    # concurrent (2x faster)
    r1, r2 = await asyncio.gather(fetch("a"), fetch("b"))

asyncio.run(main())

5.2 TaskGroup (Python 3.11+)

async def main():
    async with asyncio.TaskGroup() as tg:
        t1 = tg.create_task(fetch("a"))
        t2 = tg.create_task(fetch("b"))
        t3 = tg.create_task(fetch("c"))
    # on context exit, all tasks complete
    # if any raises, others cancelled + ExceptionGroup
    print(t1.result(), t2.result(), t3.result())

TaskGroup beats asyncio.gather: structured concurrency, auto-cancel, clear errors.

5.3 asyncio.timeout (Python 3.11+)

async def fetch_with_timeout():
    async with asyncio.timeout(5.0):
        return await slow_operation()

5.4 Five AsyncIO pitfalls

  1. Mixing blocking code: use httpx.AsyncClient instead of requests.get
  2. Nesting asyncio.run: event loop conflict. nest_asyncio is an anti-pattern
  3. Failing to keep task references: store asyncio.create_task results somewhere or GC eats them
  4. CPU-bound work: offload via run_in_executor to thread/process
  5. time.sleep inside async def: use asyncio.sleep

Part 6 — Polars: 2025 Pandas replacement

6.1 Why Polars

ItemPandasPolars
EngineNumPy (C)Rust + Arrow
Speedbaseline5-100x faster
Memoryheavy~50% of Pandas
Parallelismalmost noneauto multi-thread
Lazy executionnoyes (optimizer)
Large datahardstreaming supported

6.2 Basic usage

import polars as pl

df = pl.read_csv("data.csv")

result = (
    df
    .filter(pl.col("age") > 30)
    .group_by("country")
    .agg([
        pl.col("salary").mean().alias("avg_salary"),
        pl.col("id").count().alias("count"),
    ])
    .sort("avg_salary", descending=True)
)

6.3 Lazy Evaluation

lazy_df = pl.scan_csv("huge.csv")  # not actually read

result = (
    lazy_df
    .filter(pl.col("year") == 2024)
    .group_by("category")
    .agg(pl.col("amount").sum())
    .collect()  # now executes (optimizer plans)
)

The query optimizer plans execution like a SQL DBMS.

6.4 2025 migration guide

  • New project: Polars by default
  • Existing Pandas project: incremental migration (df.to_pandas() bridge)
  • Visualization may still be easier with Pandas (matplotlib/seaborn)
  • ML library compatibility still favors Pandas (improving)

Part 7 — 2025 AI engineering stack

7.1 Current state of LangChain

LangChain exploded in 2023, had growing pains in 2024, and 2025 is reorganized around LangGraph.

  • LangChain Core: base abstractions (Runnable)
  • LangGraph: state-based agent graph (2025 standard)
  • LangSmith: observability and evaluation

7.2 LangGraph example

from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI

class State(TypedDict):
    messages: Annotated[list, operator.add]

def agent(state: State):
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

def should_continue(state: State) -> str:
    last = state["messages"][-1]
    if last.tool_calls:
        return "tools"
    return END

workflow = StateGraph(State)
workflow.add_node("agent", agent)
workflow.add_node("tools", tool_node)
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue)
workflow.add_edge("tools", "agent")

app = workflow.compile()

Directed Graph + state machine model. Ideal for complex agent flows.

7.3 Pydantic AI (2024+)

A type-safe agent framework by the Pydantic team. Lightweight, intuitive.

from pydantic_ai import Agent
from pydantic import BaseModel

class WeatherResponse(BaseModel):
    city: str
    temp_c: float
    condition: str

agent = Agent(
    'openai:gpt-4o',
    result_type=WeatherResponse,
    system_prompt='You are a weather assistant.',
)

result = await agent.run('Weather in Seoul?')
print(result.data)  # typed as WeatherResponse

7.4 2025 AI stack recommendations

SituationRecommendation
Complex multi-step agentLangGraph
Simple type-safe agentPydantic AI
RAG-focusedLlamaIndex
Minimal production depsOpenAI SDK directly
Matching a TS teamVercel AI SDK (TS)

Part 8 — Modern Python dev environment

8.1 2025 standard toolchain

# pyproject.toml
[project]
name = "my-app"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.115",
    "pydantic>=2.9",
    "uvicorn>=0.30",
]

[dependency-groups]
dev = [
    "pytest>=8",
    "ruff>=0.7",
    "mypy>=1.13",
]

[tool.ruff]
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP", "B", "S", "C4", "PL"]

[tool.mypy]
strict = true

8.2 Ruff — 10-100x faster linter/formatter

  • Replaces Flake8, Black, isort, pyupgrade, pylint
  • Written in Rust
  • 800+ rules built-in

8.3 Type checker choice

ToolTraits
mypyoldest, slow, conservative
pyrightMS-made, fast, strict
pyreMeta-made, server mode
tyAstral-made (2025), Rust-based (in dev)

2025 pick: pyright for new, mypy for existing. Waiting on ty.

8.4 Testing

# pytest + httpx for FastAPI
import pytest
from httpx import AsyncClient, ASGITransport
from myapp.main import app

@pytest.mark.asyncio
async def test_create_user():
    async with AsyncClient(
        transport=ASGITransport(app=app), base_url="http://test"
    ) as ac:
        r = await ac.post("/users", json={"email": "a@b.com", "password": "pw"})
        assert r.status_code == 200

Part 9 — Where Python shines vs not

9.1 Shines

  • AI/ML: PyTorch, JAX, scikit-learn, Hugging Face
  • Data engineering: Airflow, dbt, Dagster
  • API servers: FastAPI productivity
  • Scientific computing: NumPy, SciPy
  • Scripting/automation: glue language
  • Education: gentle curve

9.2 Does not shine

  • CPU-bound high performance: Rust/Go/C++
  • Mobile apps: Swift/Kotlin
  • Embedded: C/Rust
  • Game engines: C++
  • Browser: JS/TS (Pyodide is niche)

2025 reality: Python is the standard for "AI, data, API" but not "for everything."


Part 10 — 6-month Python mastery roadmap

Month 1: 3.13 fundamentals

  • Full type hints (PEP 695, Union, Literal, Protocol)
  • Project management with uv
  • Ruff + mypy/pyright setup

Month 2: Pydantic + FastAPI

  • Deep Pydantic v2 (Annotated, Validators)
  • Building a real FastAPI
  • Dependency Injection patterns

Month 3: AsyncIO

  • TaskGroup, asyncio.timeout
  • Async DB with httpx, asyncpg
  • Concurrency limits (Semaphore)

Month 4: Data processing

  • Polars mastery
  • SQL + SQLAlchemy 2.0 async
  • DuckDB + Parquet

Month 5: AI engineering

  • OpenAI/Anthropic SDK
  • LangGraph or Pydantic AI
  • Vector DB (Qdrant, Pinecone, pgvector)
  • RAG pipeline construction

Month 6: Operations

  • Docker + Kubernetes deployment
  • Observability (OpenTelemetry, Prometheus)
  • CI/CD (GitHub Actions)
  • Profiling (py-spy, scalene)

Part 11 — 12-item Python checklist

  1. Know the 4 tools uv replaces (pip/poetry/pyenv/pip-tools)
  2. Know Pydantic v1 vs v2 major changes
  3. Know FastAPI Dependency Injection usage
  4. Know TaskGroup vs asyncio.gather differences
  5. Know the benefits of Polars Lazy Evaluation
  6. Know how to use Protocol and TypeIs type hints
  7. Know the SQLAlchemy 2.0 async style
  8. Know the meaning of GIL and Free-threading
  9. Know the relationship between LangGraph and LangChain
  10. Know the tools Ruff replaces
  11. Can manage config via Pydantic Settings
  12. Can test async APIs via pytest + httpx

Part 12 — 10 Python anti-patterns

  1. pip install + requirements.txt only: weak reproducibility. Use uv + uv.lock
  2. Writing Python without type hints: leaving bugs mypy/pyright would catch
  3. from X import *: namespace pollution
  4. Debugging with print(): use logging or rich
  5. except Exception: pass: silent failure. Use specific exceptions + logging
  6. Mutable default args: def f(x=[]): shares state. Use x=None then x or []
  7. iterrows in Pandas: slow. Use vectorized ops or Polars
  8. Sync libraries in async functions: blocks the event loop
  9. Not using pathlib instead of os.path: pathlib is much cleaner
  10. pip install -r requirements.txt in Docker images: breaks layer caching. Use uv sync --frozen

Closing — Python is reborn in the AI era

Python's original strengths were "productivity and learning curve." Its weaknesses were "speed and concurrency."

2024-2025:

  • Speed: solved by uv, Pydantic, Polars, Ruff with Rust engines
  • Concurrency: free-threading experiment, AsyncIO matured
  • Types: strengthened by 3.12-3.13 PEPs
  • Ecosystem: the standard language for AI engineering

"Python is slow" was a pre-2020 story. In 2025 Python is "the lingua franca of the AI era, sped up by Rust tools."

Senior engineers cannot avoid Python for a reason. In AI, data, API, and scripting, Python remains — and will remain — dominant.


Next — "LLM Complete Guide: Transformer, Attention, RLHF, RAG, Agent, Evaluation"

Season 2 Ep 6 is the 2025 engineer's core literacy: the internals of LLMs. Next:

  • How Transformer actually works
  • Attention mechanism down to the equations
  • Pre-training to SFT to RLHF to DPO flow
  • Three generations of RAG (Naive to Advanced to Agentic)
  • Agent design (ReAct, Plan-and-Execute, Multi-Agent)
  • The real difficulty of LLM evaluation (limits of LM-as-a-Judge)

Time to pry open the black box. See you next.