2.23. 데코레이터¶
데코레이터 는 함수(또는 메서드)를 다른 함수로 감싸는 구문입니다. 래퍼는 원래 호출 전후에 동작을 추가하거나, 반환 값을 교체하거나, 메타데이터를 첨부할 수 있습니다. 형태는 다음과 같습니다:
@wrapper
def f():
...
@wrapper 줄은 f = wrapper(f) 와 동등합니다 – 함수 f 가 정상적으로 만들어진 다음 wrapper 에 전달되고, 그 결과가 이름 f 에 다시 바인딩됩니다.
데코레이터는 함수를 받아 새 함수를 반환합니다.¶
2.23.1. 내장 메서드 데코레이터¶
몇 가지 데코레이터는 Python에 기본 포함되어 있으며 클래스 본문 안에서 사용됩니다.
2.23.1.1. @property¶
메서드를 계산된 속성 으로 바꿉니다. 호출자는 마치 일반 속성인 것처럼(괄호 없이) 접근하지만, 읽을 때마다 메서드가 실행됩니다:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14159 * self.radius * self.radius
c = Circle(5)
print(c.area) # 78.53975 -- no parentheses
단순해 보이는 속성에 약간의 계산이 뒤에 필요할 때 사용하세요. 작업이 비용이 크다면 일반 메서드를 선호하세요 – 호출자는 속성 읽기가 느릴 것이라고 예상하지 않습니다.
2.23.1.2. @classmethod¶
인스턴스 대신 클래스 를 첫 번째 인수로 받는 메서드를 정의합니다. 첫 번째 매개변수는 관례적으로 cls 로 이름 짓습니다:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def origin(cls):
return cls(0, 0)
p = Point.origin()
클래스 메서드는 대체 생성자 를 제공하는 표준적인 방법입니다 – 기본이 아닌 방식으로 만들어진 인스턴스를 반환하는 팩토리 함수입니다.
2.23.1.3. @staticmethod¶
인스턴스도 클래스도 받지 않는 메서드를 정의합니다 – 조직적인 이유로 클래스 네임스페이스 안에 존재하는 그냥 평범한 함수입니다:
class Temperature:
@staticmethod
def c_to_f(c):
return c * 9 / 5 + 32
Temperature.c_to_f(100) # 212.0
아껴서 사용하세요. 함수가 정말로 클래스의 상태와 아무 관련이 없다면, 보통 모듈 수준의 일반 함수가 더 깔끔합니다.
2.23.2. 사용자 정의 데코레이터 작성하기¶
데코레이터는 함수를 받아 함수를 반환하는 함수입니다. 최소 형태:
def log_calls(func):
def wrapper(*args, **kwargs):
print("calling", func.__name__)
return func(*args, **kwargs)
return wrapper
@log_calls
def add(a, b):
return a + b
add(2, 3)
출력:
calling add
wrapper 는 func 를 클로저로 감싸고 모든 것을 그것에 전달합니다. *args / **kwargs 덕분에 두 개의 인수를 받는 함수뿐만 아니라 어떤 함수에서도 작동합니다. 이 패턴은 더 정교한 데코레이터(타이밍, 캐싱, 실패 시 재시도)의 기초이지만 핵심은 항상 동일합니다: 함수를 받아 함수를 반환합니다.