https://comgu.tistory.com/entry/Python-데코레이터Decorator-1-데코레이터-중첩-데코레이터
https://comgu.tistory.com/entry/Python-데코레이터Decorator-2-동적-데코레이터
데코레이터에 대한 마지막 주제로, 클래스형 데코레이터에 대해 다뤄보겠다.
클래스형 데코레이터
클래스형 데코레이터는 데코레이터를 클래스 형태로 구현하는 방식이다.
함수형 데코레이터와 마찬가지로, 클래스형 데코레이터도 함수나 메서드에 특정 기능을 추가하거나 수정할 때 사용된다.
클래스형 데코레이터의 핵심은 클래스의 __call__ 메소드를 정의하여 인스턴스가 호출 가능하도록 만드는 것이다.
실제로 함수도 "function" 클래스의 인스턴스이고 __call__ 메소드를 갖기 때문에 함수명()의 형태로 호출이 가능한 것이다.
class MyDecorator:
def __init__(self, func):
self.func = func # 데코레이트할 함수 저장
def __call__(self, *args, **kwargs):
print("함수 실행 이전")
result = self.func(*args, **kwargs)
print("함수 실행 이후")
return result
@MyDecorator
def add(x, y):
print(f"{x} + {y} = {x + y}")
add(3, 4)
함수 실행 이전
3 + 4 = 7
함수 실행 이후
실행순서
- @MyDecorator가 데코레이트된 함수(즉 add)에 적용될 때, MyDecorator 클래스의 __init__ 메서드가 호출되어 add가 func으로 전달된다.
- 데코레이트된 함수(add)가 호출될 때, __call__ 메서드가 실행된다.
- __call__ 메서드 안에서 추가 작업을 수행한 후 원래의 함수(self.func)를 호출한다.
만약 add 함수가 데코레이터를 사용하지 않았다면, 클래스형 데코레이터를 사용하기 위해 아래와 같은 방식을 사용한 것과 동일하다.
def add(x, y):
print(f"{x} + {y} = {x + y}")
MyDecorator(add)(3, 4)
함수 실행 이전
3 + 4 = 7
함수 실행 이후
클래스형 데코레이터의 장점
- 상태 유지: 클래스 내부에 상태를 저장할 수 있어, 함수 호출 횟수 등을 추적할 수 있다.
- 구조화된 코드: 복잡한 데코레이터 로직을 객체 지향적으로 관리할 수 있다.
상태를 저장하는 클래스형 데코레이터
클래스형 데코레이터를 쓰면, 클래스 내부에 상태를 저장하여 관리할 수 있다.
class CallCounter:
def __init__(self, func):
self.func = func
self.count = 0 # 호출 횟수 추적
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} 함수 실행 카운트: {self.count}")
return self.func(*args, **kwargs)
@CallCounter
def greet(name):
print(f"Hello, {name}!")
greet("AAA")
greet("BBB")
greet("CCC")
greet 함수 실행 카운트: 1
Hello, AAA!
greet 함수 실행 카운트: 2
Hello, BBB!
greet 함수 실행 카운트: 3
Hello, CCC!
만약 greet 함수가 데코레이터를 사용하지 않았다면, 클래스형 데코레이터를 사용하기 위해 아래와 같은 방식을 사용한 것과 동일하다.
def greet(name):
print(f"Hello, {name}!")
CallCounter(greet)("AAA")
CallCounter(greet)("BBB")
CallCounter(greet)("CCC")
greet 함수 실행 카운트: 1
Hello, AAA!
greet 함수 실행 카운트: 1
Hello, BBB!
greet 함수 실행 카운트: 1
Hello, CCC!
(고급) 파라미터를 받는 클래스형 데코레이터
클래스형 데코레이터에 인자를 전달하려면, 데코레이터의 역할을 하는 클래스의 인스턴스가 내부의 wrapper 함수를 한번 더 리턴할 수 있도록 해주면 된다.
class Repeat:
def __init__(self, times):
self.times = times
def __call__(self, func):
def wrapper(*args, **kwargs):
for _ in range(self.times):
func(*args, **kwargs)
return wrapper
@Repeat(3)
def hello():
print("Hello!")
hello()
Hello!
Hello!
Hello!
만약 hello 함수가 데코레이터를 사용하지 않았다면, 클래스형 데코레이터를 사용하기 위해 아래와 같은 방식을 사용한 것과 동일하다.
def hello():
print("Hello!")
Repeat(3)(hello)()
Hello!
Hello!
Hello!
이것으로 데코레이터 시리즈의 마지막 글을 마친다.
(나중에 더 다룰 주제가 있으면 4탄 이상으로 추가할 생각이다)
'Python' 카테고리의 다른 글
[Python] 제너레이터(Generator) (1) | 2024.12.14 |
---|---|
[Python] 데코레이터(Decorator) 2 - 동적 데코레이터 (0) | 2024.12.12 |
[Python] 데코레이터(Decorator) 1 - 데코레이터, 중첩 데코레이터 (0) | 2024.12.11 |
[Python] 클로저(Closure) 함수 (0) | 2024.12.11 |
[Python] 객체의 shallow copy와 deep copy (1) | 2024.12.10 |