Python ํ•™์Šต ๊ฐ€์ด๋“œ

๋ฌธ๋ฒ•, ํ”„๋ ˆ์ž„์›Œํฌ, ํŒจํ‚ค์ง€ โ€” ์ฝ”๋“œ ๋ ˆ๋ฒจ๋กœ ๋™์ž‘ ์›๋ฆฌ ์ •๋ฆฌ

๐Ÿ“– ๋ฌธ๋ฒ• & ๊ธฐ์ดˆ

๐Ÿ”„

Generator์™€ yield โ€” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์•ˆ ๋จน๋Š” ์ดํ„ฐ๋ ˆ์ด์…˜์˜ ์›๋ฆฌ

yield๊ฐ€ ํ•จ์ˆ˜ ์‹คํ–‰์„ "์ผ์‹œ ์ •์ง€"์‹œํ‚ค๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜

Generator๋Š” ๊ฐ’์„ ํ•œ๊บผ๋ฒˆ์— ๋งŒ๋“ค์ง€ ์•Š๊ณ  yield๋กœ ํ•˜๋‚˜์”ฉ ๋‚ด๋ณด๋‚ธ๋‹ค. 10GB ํŒŒ์ผ์„ ํ•œ ์ค„์”ฉ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๊ฐ€ ์ด๊ฒƒ์ด๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ ํ•จ์ˆ˜์˜ ์Šคํƒ ํ”„๋ ˆ์ž„์„ ๋ณด์กดํ•˜๋ฉด์„œ ์‹คํ–‰์„ ์ค‘๋‹จ/์žฌ๊ฐœํ•œ๋‹ค.

๐ŸŽ€

Decorator ๋‚ด๋ถ€ ๊ตฌ์กฐ โ€” @๊ฐ€ ์‹ค์ œ๋กœ ํ•˜๋Š” ์ผ

ํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„์„œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ โ€” ๊ทธ๊ฒŒ ์ „๋ถ€๋‹ค

@decorator๋Š” ๋ฌธ๋ฒ•์  ์„คํƒ•(syntactic sugar)์ด๋‹ค. func = decorator(func)์™€ ๋™์ผํ•˜๋‹ค. ํด๋กœ์ €์™€ *args/**kwargs ์กฐํ•ฉ์œผ๋กœ ์›๋ณธ ํ•จ์ˆ˜๋ฅผ ๊ฐ์‹ธ๋Š” ํŒจํ„ด.

๐Ÿšช

Context Manager โ€” with๋ฌธ์ด ์‹ค์ œ๋กœ ํ•˜๋Š” ์ผ

__enter__๊ณผ __exit__๋กœ ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ๋ฅผ ๋ณด์žฅํ•˜๋Š” ํ”„๋กœํ† ์ฝœ

with open("f") as f: ์˜ with๋Š” __enter__()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ฆฌ์†Œ์Šค๋ฅผ ์–ป๊ณ , ๋ธ”๋ก์ด ๋๋‚˜๋ฉด(์—๋Ÿฌ๊ฐ€ ๋‚˜๋“  ์•ˆ ๋‚˜๋“ ) __exit__()๋กœ ์ •๋ฆฌํ•œ๋‹ค. contextlib.contextmanager๋กœ generator ๊ธฐ๋ฐ˜ ๊ตฌํ˜„๋„ ๊ฐ€๋Šฅ.

๐Ÿท๏ธ

Type Hints โ€” ๋Ÿฐํƒ€์ž„์—์„œ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ํ•œ๋‹ค

Python์˜ ํƒ€์ž… ํžŒํŠธ๊ฐ€ "ํžŒํŠธ"์ธ ์ด์œ ์™€, Pydantic์ด ์ด๊ฑธ ๊ทน๋ณตํ•˜๋Š” ๋ฐฉ๋ฒ•

Python์˜ type hint(: int, -> str)๋Š” ๋Ÿฐํƒ€์ž„์— ๊ฒ€์‚ฌ๋˜์ง€ ์•Š๋Š”๋‹ค. mypy ๊ฐ™์€ ์ •์  ๋ถ„์„ ๋„๊ตฌ๊ฐ€ ์ฝ์„ ๋ฟ์ด๋‹ค. Pydantic์€ ์ด ํ•œ๊ณ„๋ฅผ __init_subclass__์™€ ๋ชจ๋ธ ๊ฒ€์ฆ์œผ๋กœ ๋„˜์–ด์„œ์„œ ๋Ÿฐํƒ€์ž„ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

โœณ๏ธ

Keyword-only ์ธ์ž โ€” `*,` ๊ฐ€ ๋ญ”์ง€, ์™œ ์“ฐ๋Š”์ง€

`def f(a, b, *, c)` ์˜ ๊ทธ ๋ณ„ ํ•˜๋‚˜

Python์˜ `*,`๋Š” "์—ฌ๊ธฐ๋ถ€ํ„ฐ๋Š” ํ‚ค์›Œ๋“œ๋กœ๋งŒ ๋ฐ›๋Š”๋‹ค"๋Š” ๊ตฌ๋ถ„์„ ์ด๋‹ค. ์œ„์น˜ ์ธ์ž๋กœ ๋„˜๊ธฐ๋ฉด TypeError. ํ˜ธ์ถœ ์˜๋„๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•˜๊ณ  ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ์— ๊ฐ•ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. Ruby์—๋Š” `:` ํ‚ค์›Œ๋“œ ์ธ์ž ์ž์ฒด๊ฐ€ ์ฒ˜์Œ๋ถ€ํ„ฐ keyword-only๋ผ ๋ณ„๋„ ๋ฌธ๋ฒ•์ด ํ•„์š” ์—†๋‹ค.

โšก FastAPI

๐Ÿ—๏ธ

FastAPI ์•„ํ‚คํ…์ฒ˜ โ€” Starlette + Pydantic + Uvicorn์˜ ์กฐํ•ฉ

FastAPI๊ฐ€ "๋น ๋ฅด๋‹ค"๊ณ  ๋งํ•˜๋Š” ์ด์œ ์˜ ์‹ค์ฒด

FastAPI ์ž์ฒด๋Š” "ํ”„๋ ˆ์ž„์›Œํฌ ์œ„์˜ ํ”„๋ ˆ์ž„์›Œํฌ"๋‹ค. HTTP๋Š” Starlette๊ฐ€, ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์€ Pydantic์ด, ASGI ์„œ๋ฒ„๋Š” Uvicorn์ด ๋‹ด๋‹นํ•œ๋‹ค. FastAPI๋Š” ์ด๊ฒƒ๋“ค์„ ํƒ€์ž… ํžŒํŠธ ๊ธฐ๋ฐ˜ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ฌถ์€ ๊ฒƒ.

๐Ÿ’‰

FastAPI Depends() โ€” ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋กœ DIํ•˜๋Š” ๋ฐฉ๋ฒ•

DB ์„ธ์…˜, ์ธ์ฆ, ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ํ•จ์ˆ˜ ์ธ์ž๋กœ ์ฃผ์ž…ํ•˜๋Š” ํŒจํ„ด

FastAPI์˜ Depends()๋Š” ํ•จ์ˆ˜๋ฅผ ์ธ์ž์˜ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋„ฃ์œผ๋ฉด ์ž๋™์œผ๋กœ ํ˜ธ์ถœ/์ฃผ์ž…ํ•ด์ฃผ๋Š” DI ์‹œ์Šคํ…œ์ด๋‹ค. ์ค‘์ฒฉ ๊ฐ€๋Šฅํ•˜๊ณ , generator๋ฅผ ์“ฐ๋ฉด cleanup๋„ ๋ณด์žฅ๋œ๋‹ค.

๐Ÿ”€

FastAPI์˜ async/await โ€” def์™€ async def์˜ ์ฐจ์ด

async def๋ฅผ ์“ฐ๋ฉด ๋นจ๋ผ์ง€๋‚˜? ๊ทธ๊ฑด ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค

FastAPI์—์„œ def๋Š” ์Šค๋ ˆ๋“œํ’€์—์„œ, async def๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ์‹คํ–‰๋œ๋‹ค. I/O ๋Œ€๊ธฐ๊ฐ€ ๋งŽ์œผ๋ฉด async๊ฐ€ ์œ ๋ฆฌํ•˜๊ณ , CPU ๋ฐ”์šด๋“œ๋ฉด def๊ฐ€ ๋‚ซ๋‹ค. ๋‘˜ ๋‹ค ์ง€์›ํ•˜๋Š” ๊ฒŒ FastAPI์˜ ๊ฐ•์ .

๐ŸŽธ Django

๐Ÿ—„๏ธ

Django ORM ๋‚ด๋ถ€ โ€” QuerySet์ด lazyํ•œ ์ด์œ 

filter().exclude().order_by()๋ฅผ ์ฒด์ด๋‹ํ•ด๋„ SQL์ด ์•ˆ ๋‚˜๊ฐ€๋Š” ์›๋ฆฌ

Django์˜ QuerySet์€ ํ‰๊ฐ€(evaluate)๋˜๊ธฐ ์ „๊นŒ์ง€ SQL์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. filter/exclude/order_by๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ SQL ์กฐ๊ฑด์„ ์Œ“๊ธฐ๋งŒ ํ•˜๊ณ , list()/for/[0] ๋“ฑ์œผ๋กœ ์ ‘๊ทผํ•  ๋•Œ ๋น„๋กœ์†Œ DB์— ์ฟผ๋ฆฌํ•œ๋‹ค.

๐Ÿง…

Django Middleware โ€” ์š”์ฒญ/์‘๋‹ต์„ ๊ฐ์‹ธ๋Š” ์–‘ํŒŒ ๊ตฌ์กฐ

MIDDLEWARE ์„ค์ • ์ˆœ์„œ๊ฐ€ ์™œ ์ค‘์š”ํ•œ์ง€, ๋‚ด๋ถ€์—์„œ ์–ด๋–ป๊ฒŒ ์ฒด์ด๋‹๋˜๋Š”์ง€

Django์˜ ๋ฏธ๋“ค์›จ์–ด๋Š” ์–‘ํŒŒ ๊ป์งˆ์ฒ˜๋Ÿผ ๊ฒน๊ฒน์ด ๊ฐ์‹ธ๋Š” ๊ตฌ์กฐ๋‹ค. ์š”์ฒญ์€ ๋ฐ”๊นฅ์—์„œ ์•ˆ์œผ๋กœ, ์‘๋‹ต์€ ์•ˆ์—์„œ ๋ฐ–์œผ๋กœ ํ†ต๊ณผํ•œ๋‹ค. MIDDLEWARE ๋ฆฌ์ŠคํŠธ์˜ ์ˆœ์„œ๊ฐ€ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.

๐Ÿ“ก

Django Signals โ€” ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ๋А์Šจํ•œ ๊ฒฐํ•ฉ

post_save, pre_delete๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€

Django Signal์€ Observer ํŒจํ„ด์˜ ๊ตฌํ˜„์ด๋‹ค. ๋ชจ๋ธ์ด ์ €์žฅ/์‚ญ์ œ๋  ๋•Œ ๋“ฑ๋ก๋œ receiver ํ•จ์ˆ˜๋ฅผ ์ž๋™์œผ๋กœ ํ˜ธ์ถœํ•œ๋‹ค. ํŽธ๋ฆฌํ•˜์ง€๋งŒ ๋‚จ์šฉํ•˜๋ฉด ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์ง„๋‹ค.

๐Ÿ“ฆ ์ž์ฃผ ์“ฐ๋Š” ํŒจํ‚ค์ง€

๐ŸŒ

requests ๋‚ด๋ถ€ ๊ตฌ์กฐ โ€” requests.get()์ด ์‹ค์ œ๋กœ ํ•˜๋Š” ์ผ

Session, PreparedRequest, HTTPAdapter, urllib3๊นŒ์ง€์˜ ํ˜ธ์ถœ ์ฒด์ธ

requests.get(url)์€ ๋‚ด๋ถ€์ ์œผ๋กœ Session ์ƒ์„ฑ โ†’ PreparedRequest ์กฐ๋ฆฝ โ†’ HTTPAdapter ์„ ํƒ โ†’ urllib3.PoolManager๋กœ ์‹ค์ œ TCP ์—ฐ๊ฒฐ์„ ๊ฑฐ์นœ๋‹ค. ์ด ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์•Œ๋ฉด ์ปค๋„ฅ์…˜ ํ’€, ํƒ€์ž„์•„์›ƒ, ์žฌ์‹œ๋„๋ฅผ ์ œ๋Œ€๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ”

Pydantic ๋‚ด๋ถ€ โ€” ํƒ€์ž… ํžŒํŠธ๊ฐ€ ๋Ÿฐํƒ€์ž„ ๊ฒ€์ฆ์ด ๋˜๋Š” ๊ณผ์ •

__annotations__ โ†’ Rust ์ฝ”์–ด(pydantic-core) โ†’ ๊ฒ€์ฆ ์‹คํ–‰

Pydantic v2๋Š” ๋ชจ๋ธ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•  ๋•Œ __annotations__๋ฅผ ์ฝ์–ด์„œ Rust๋กœ ์ž‘์„ฑ๋œ pydantic-core์˜ ๊ฒ€์ฆ ์Šคํ‚ค๋งˆ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. __init__์—์„œ ๊ฐ’์„ ๋„ฃ์„ ๋•Œ ์ด ์Šคํ‚ค๋งˆ๋กœ ๊ฒ€์ฆ์ด ์‹คํ–‰๋œ๋‹ค.

๐Ÿ–ฑ๏ธ

Click โ€” Python CLI ๋„๊ตฌ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฐ€์žฅ ๊น”๋”ํ•œ ๋ฐฉ๋ฒ•

decorator ๊ธฐ๋ฐ˜ CLI ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋‚ด๋ถ€ ๋™์ž‘

Click์€ decorator๋กœ CLI ์ธ์ž/์˜ต์…˜์„ ์ •์˜ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค. argparse๋ณด๋‹ค ์ง๊ด€์ ์ด๊ณ , Flask ๊ฐœ๋ฐœ์ž(Armin Ronacher)๊ฐ€ ๋งŒ๋“ค์—ˆ๋‹ค. @click.command + @click.option์œผ๋กœ CLI๊ฐ€ ์™„์„ฑ๋œ๋‹ค.