3 단계 구조
일반 decorator 는 2 단계 — 바깥 함수가 wrapped 함수 받고, 안의 wrapper 가 일 함. 인자 받는 decorator (@retry(times=3) 처럼 짜는) 는 *3* 단계 — 바깥 함수가 인자 받고, 일반 decorator 반환, 그게 wrapper 반환. 첫 단계가 "decorator factory" — 설정에 따라 decorator 제조.
왜 3 단계 — 각 단계가 뭐 하나
레벨 1 — factory 함수 — 설정 인자 받음 (retry(times=3)). 레벨 2 반환. 레벨 2 — 실제 decorator — 감쌀 함수 받음. 레벨 3 반환. 레벨 3 — wrapper — *args, **kwargs 받고 일 함. 3 단계 이유 — @retry(times=3) 가 "retry(times=3) 호출, 그 결과를 decorator 로 적용" 의미.
Closure 가 설정 보관
레벨 3 의 wrapper 는 레벨 1 의 times=3 알아야 해. 둘러싼 scope 통해 접근 — closure. factory 가 호출될 때마다 새 decorator 만들어서 각 호출 사이트마다 다른 설정 정확히 캡쳐.
@retry 가 감쌀 함수를 times 인자로 사용하려 함. 에러 메시지 헷갈려. 해결책 항상 — 괄호, 인자 안 넘겨도 — @retry().
옵션 인자 트릭 — 그리고 안 쓸 때
일부 decorator 는 @deco 와 @deco(args) 둘 다 지원하려 함. 첫 인자가 함수 (인자 없는 경우) 인지 다른 거 (factory 경우) 인지 체크 포함. 영리하지만 Python decorator 코드의 큰 혼란 원인 중 하나. 야생의 잘 디자인된 decorator 는 무조건 괄호 요구 — 디폴트 설정의 @retry() 가 명료함의 대가.