두 기능이 함께 나타날 때 읽는 순서
매직 메서드 자체에도 decorator가 붙을 수 있지만 두 역할은 여전히 다르다. 먼저 매직 메서드가 객체 protocol에서 어떤 호출을 받는지 보고, 그 바깥 decorator가 호출 전후 무엇을 추가하는지 본다. 한 층씩 풀어 쓰면 오류가 wrapper인지 연산 의미인지 분리된다.
리뷰에서는 숨겨진 동작의 범위를 묻는다. 함수 이름만 보고 알 수 없는 I/O나 상태 변경을 decorator가 추가하는지, +가 예상 밖의 외부 작업을 하는지 확인한다. 짧은 문법이 많은 책임을 감출수록 문서와 테스트가 더 필요하다.
데코레이터를 겹쳐 쓸 때는 아래쪽 데코레이터가 먼저 원래 함수를 감싸고, 호출할 때는 바깥 wrapper부터 실행된다는 두 시점을 나눠야 합니다. 인증, 재시도, 로깅 순서를 바꾸면 실패 시 기록 여부와 재시도마다 인증을 반복하는지가 달라질 수 있습니다. Wrapper가 원래 함수의 인자와 반환값을 그대로 전달하는지, 예외를 숨기지 않는지, 함수 메타데이터를 보존하는지도 테스트합니다.
매직 메서드는 문법을 예쁘게 만드는 대신 사용자가 이미 기대하는 의미를 따라야 합니다. 두 객체의 +가 새 객체를 만드는지 원본을 바꾸는지, 다른 타입과 더할 때 무엇을 반환할지, ==와 hash의 관계를 어떻게 유지할지를 정해야 합니다. 지원하지 않는 피연산자를 임의로 변환하면 조용한 오류가 생길 수 있으므로 Python이 반대쪽 연산이나 오류 처리를 시도할 수 있는 반환 방식도 고려합니다.
둘을 함께 쓰는 코드에서는 먼저 클래스 문법이 어떤 매직 메서드 호출로 바뀌는지 확인한 뒤, 그 메서드가 데코레이터로 감싸졌는지 추적합니다. 측정 데코레이터가 __call__을 감싸면 객체 생성이 아니라 객체 호출 시간을 재고, __init__을 감싸면 반환값을 바꾸어서는 안 됩니다. 편리한 문법이 실제 실행 지점을 가리기 때문에 호출 경계를 작은 테스트로 고정하는 것이 안전합니다.