파이썬의 데코레이터는 역사적으로 반복되는 동작을 함수와 메소드 주위에 캡슐화하여 코드를 더 간결하고 읽기 쉽게 만들기 위한 방법으로 등장했습니다. @decorator 구문이 등장하기 전에는 명시적으로 사용되었으며, 이는 코드 이해를 복잡하게 만들었습니다. 오늘날 데코레이터는 로직 구성, 반복적인 검사, 로깅, 캐싱 및 기타 작업에서 핵심적인 역할을 합니다.
데코레이터 작업 시 문제는 함수, 인스턴스 메소드 및 정적/클래스 메소드 간의 차이를 정확하게 처리하는 것입니다. 종종 메소드 정보 손실, self의 늦은/빠른 바인딩, 함수 서명과 관련된 오류가 발생합니다.
해결 방안은 범용 데코레이터를 작성할 때 functools.wraps 모듈을 사용하여 메타데이터를 유지하고, 데코레이팅할 객체의 유형을 주의 깊게 고려하는 것입니다(예: 인스턴스 메소드가 첫 번째 인자로 self를 받는다는 점을 올바르게 고려합니다).
코드 예제:
import functools def my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f"함수 전: {func.__name__}") result = func(*args, **kwargs) print(f"함수 후: {func.__name__}") return result return wrapper class Example: @my_decorator def method(self, x): print(f"{x}로 메소드 호출") ex = Example() ex.method(5)
주요 특징:
functools.wraps를 사용하는 것이 좋습니다.함수를 위해 작성된 데코레이터를 클래스 메소드에서 사용할 경우, functools.wraps를 사용하는 것이 필수적인가? self는 어떻게 되는가?
아니요, 데코레이터 자체는 작동하지만, wraps 없이 함수 이름, IDE 지원 및 문서가 손실됩니다. Self는 여전히 첫 번째 매개변수이지만, 메타데이터 손실로 디버깅 및 리플렉션이 어려워집니다.
def bad_decorator(f): def wrapper(*args, **kwargs): print("decorated") return f(*args, **kwargs) return wrapper class Test: @bad_decorator def foo(self): pass print(Test().foo.__name__) # wrapper
같은 데코레이터를 인스턴스 메소드와 정적 메소드 모두에 적용할 수 있는가?
가능하지만, 정적 메소드는 self를 첫 번째 인수로 받지 않는다는 것을 기억해야 합니다. 데코레이터가 self와 작동할 것으로 기대된다면, @staticmethod / @classmethod에서 오류가 발생합니다.
데코레이터는 메소드의 서명과 자동 완성에 어떤 영향을 미치는가?
가장 간단하게 말하면: functools.wraps 없이 서명과 문서 문자열이 손실되어 IDE와 많은 자동 완성 도구들이 제대로 작동하지 않습니다.
부정적인 케이스: 모든 클래스 메소드에서 functools.wraps가 없는 데코레이터.
장점: 빠른 프로토타입, 작동함.
단점: 스택에서 오류를 검색할 수 없고, IDE가 서명을 제안하지 않음.
긍정적인 케이스: functools.wraps를 사용하는 데코레이터, 코드가 문서화됨.
장점: 가독성, 유지보수, IDE 편의성.
단점: 구문 및 주의 최소 추가.