@ 가 진짜 하는 일
decorator 는 함수 받아서 함수 반환하는 함수. 정의 위의 @decorator 문법은 단지 단축형 — @deco + def f(): ... 가 def f(): ... 다음 f = deco(f) 와 정확히 같음. 그게 전부. 이거 보면 모든 decorator 가 마법 아니게 돼.
감싸기 패턴 — 정석 모양
다른 함수를 입력으로 받는 함수 (decorator) 정의. 안에서 wrapper 함수 정의 — 원래 함수 호출, 호출 전/후/주변에 추가 로직 가능. wrapper 반환. 사용자가 @deco 쓰면 wrapper 가 원래 이름에 바인딩.
왜 wrapper 에 *args / **kwargs 필요한가
decorator 는 감싸는 함수가 어떤 인자 받는지 몰라. wrapper 가 def wrapper(): 로 하드코딩하면 0 인자 함수에서만 작동. idiomatic 모양 — def wrapper(*args, **kwargs): return fn(*args, **kwargs). wrapper 가 모든 거 받고 모든 거 forward. 추가 로직은 호출 전/후에.
decorator 가 좋은 일
cross-cutting concerns. 모든 API 호출 주변에 로깅. 시간 측정. 비싼 계산 캐싱. 인증 체크. 재시도 로직. 함수 본문 안이 아니라 개념적으로 함수를 감싸는 모든 거. 패턴 — "함수 자체를 안 건드리고 모든 호출 경계에 동작 추가".
스택 — 한 함수에 여러 decorator
decorator 는 아래에서 위로 적용. @a + @b + def f(): 는 f = a(b(f)). 함수에 가장 가까운 decorator 가 먼저. 순서가 중요할 때 (logging-then-cache vs cache-then-logging 다른 결과) 중요.