Skip to content

✍️ 필사 모드: Python Complete Guide — FastAPI, AsyncIO, Pydantic, uv, Polars, AI Engineering (Season 2 Ep 5, 2025)

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

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.

현재 단락 (1/346)

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

작성 글자: 0원문 글자: 13,501작성 단락: 0/346