왜 generic — 타입을 parametric 하게
가끔 함수나 클래스가 어떤 타입에든 작동, 근데 "입력과 출력이 같은 타입" 표현 원함. def first(items: list[T]) -> T 가 "T 의 list 가 T 반환". T 가 타입 변수 — 타입 체커가 호출별 해결하는 placeholder.
TypeVar — 일꾼
T = TypeVar("T") 가 타입 변수 생성. 함수 시그니처 또는 클래스 파라미터로 사용 (베이스에 Generic[T] 와). Bound 변수 — T = TypeVar("T", bound=Comparable) — T 를 Comparable 의 서브타입으로 제한. Constrained — T = TypeVar("T", int, str) — T 를 특정 set 의 하나로 제한.
Generic 클래스 — Stack[int] vs Stack[str]
원소 타입에 generic 한 클래스. 시그니처에 T 사용하는 메서드 가진 class Stack(Generic[T]). Stack[int]() 가 int stack 생성, Stack[str]() 가 string stack 생성. 타입 체커가 원소 타입 추론 + 연산 검증.
Self — "나와 같은 클래스"
자기 클래스 반환하는 메서드가 종종 "Self 반환" 말하고 싶음. 3.11 전엔 TypeVar("T", bound="MyClass") 우회. Python 3.11 이 정확히 이 케이스용 typing.Self 추가 — def chain(self) -> Self: 가 "실제로 호출한 클래스 무엇이든 반환". 유연 인터페이스와 서브클래스의 factory 메서드에 유용.
ParamSpec — 전체 호출 시그니처 보존
함수 감싸는 데코레이터엔 "wrapper 가 wrapped 함수와 같은 인자 받음" 말하고 싶음. P = ParamSpec("P") 가 전체 파라미터 list (positional + keyword) 캡쳐. 데코레이터 힌트 — def wrap(fn: Callable[P, R]) -> Callable[P, R]. FastAPI 같은 도구가 많이 사용.