레슨 10 / 11·4개 토픽
비동기 프로그래밍과 타입 힌팅
async/await 기초
asyncio는 Python의 비동기 프로그래밍 라이브러리입니다. async def로 코루틴을 정의하고, await로 비동기 작업의 완료를 기다립니다. I/O 바운드 작업(네트워크 요청, 파일 읽기 등)에서 동시성을 확보할 수 있습니다.
python
import asyncio
# 기본 코루틴
async def greet(name, delay):
await asyncio.sleep(delay) # 비동기 대기
print(f"안녕하세요, {name}!")
return f"{name} 인사 완료"
# 단일 코루틴 실행
asyncio.run(greet("Alice", 1))
# asyncio.gather()로 동시 실행
async def main():
# 3개 작업을 동시에 시작 (총 2초, 순차라면 6초)
results = await asyncio.gather(
greet("Alice", 2),
greet("Bob", 1),
greet("Charlie", 1.5),
)
print(f"결과: {results}")
asyncio.run(main())비동기 실전 패턴
python
import asyncio
# 비동기 HTTP 요청 시뮬레이션
async def fetch_url(url: str) -> dict:
print(f"요청 시작: {url}")
await asyncio.sleep(1) # 네트워크 지연 시뮬레이션
return {"url": url, "status": 200}
async def fetch_all():
urls = [
"https://api.example.com/users",
"https://api.example.com/posts",
"https://api.example.com/comments",
]
# 모든 요청을 동시에 실행
tasks = [fetch_url(url) for url in urls]
results = await asyncio.gather(*tasks)
for r in results:
print(f" {r['url']} → {r['status']}")
# 타임아웃 처리
async def with_timeout():
try:
result = await asyncio.wait_for(
fetch_url("https://slow-api.com"),
timeout=0.5
)
except asyncio.TimeoutError:
print("타임아웃 발생!")
# 비동기 이터레이터
async def countdown(n):
for i in range(n, 0, -1):
yield i
await asyncio.sleep(0.5)
async def main():
async for num in countdown(5):
print(num)타입 힌팅 기초
타입 힌트는 코드의 가독성을 높이고 IDE 자동 완성과 정적 분석 도구(mypy)를 활용할 수 있게 합니다. Python 3.9+에서는 내장 타입을 직접 사용할 수 있고, 3.10+에서는 X | Y 유니온 구문을 지원합니다.
python
# 기본 타입 힌트
def greet(name: str) -> str:
return f"Hello, {name}!"
# 컬렉션 타입 (Python 3.9+)
def average(numbers: list[float]) -> float:
return sum(numbers) / len(numbers)
def word_count(text: str) -> dict[str, int]:
counts: dict[str, int] = {}
for word in text.split():
counts[word] = counts.get(word, 0) + 1
return counts
# Optional과 Union (Python 3.10+)
def find_user(user_id: int) -> dict | None:
users = {1: {"name": "Alice"}, 2: {"name": "Bob"}}
return users.get(user_id)
def parse_input(value: str | int) -> str:
return str(value)
# 이전 버전 호환 (3.9 이전)
from typing import Optional, Union, List, Dict
def legacy_find(user_id: int) -> Optional[Dict[str, str]]:
passtyping 모듈 심화
python
from typing import TypeVar, Generic, Protocol, Callable
# TypeVar — 제네릭 함수
T = TypeVar("T")
def first(items: list[T]) -> T:
return items[0]
print(first([1, 2, 3])) # int 추론
print(first(["a", "b"])) # str 추론
# Generic 클래스
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
int_stack: Stack[int] = Stack()
int_stack.push(42)
# Protocol — 구조적 타이핑 (덕 타이핑)
class Drawable(Protocol):
def draw(self) -> str: ...
class Circle:
def draw(self) -> str:
return "○"
class Square:
def draw(self) -> str:
return "□"
def render(shape: Drawable) -> None:
print(shape.draw()) # Circle, Square 모두 가능
# Callable 타입
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
print(apply(lambda x, y: x + y, 3, 4)) # 7- •
async def— 코루틴(비동기 함수)을 정의하는 키워드 - •
await— 비동기 작업의 완료를 기다림 (async 함수 안에서만 사용) - •
asyncio.run()— 이벤트 루프를 시작하고 코루틴을 실행 - •
asyncio.gather()— 여러 코루틴을 동시에 실행하고 결과를 모음 - •
TypeVar— 제네릭 함수나 클래스에서 타입 매개변수 정의 - •
Generic[T]— 타입 매개변수를 가진 제네릭 클래스 생성 - •
Protocol— 구조적 타이핑(덕 타이핑)을 위한 인터페이스 정의
💡
asyncio는 CPU 바운드 작업에는 적합하지 않습니다. CPU 집약적 작업은 multiprocessing이나 concurrent.futures.ProcessPoolExecutor를 사용하세요. 타입 힌트는 런타임에 강제되지 않으므로, mypy로 정적 분석을 실행해야 실질적인 타입 검사가 이루어집니다.