[Python] 파이썬 데코레이터
UNIT42 데코레이터 사용하기
데코레이터 만들기
데코레이터는 함수 안에서 함수를 만들고 반환하는 클로저입니다. 어떤 함수가 있을 때 해당 함수를 직접 수정하지 않고 함수에 기능을 추가하고자 할 때 데코레이터를 사용합니다.
def trace(func):
def wrapper():
print(func.__name__, '함수 시작')
func()
print(func.__name__, '함수 끝')
return wrapper
def hello():
print('hello')
trace_hello = trace(hello) # wrapper 함수
trace_hello() # wrapper -> print, func, print 실행
def world():
print('world')
trace_world = trace(world)
trace_word()
데코레이터는 @를 사용하여 간편하게 사용할 수 있습니다.
@데코레이터
def 함수이름():
코드
위에서 만든 데코레이터, trace 함수를 hello 함수에 동일하게 적용해봅시다.
@trace
def hello():
print('hello')
hello()
매개변수와 반환값을 처리하는 데코레이터
def trace(func):
def wrapper(a,b):
func(a,b)
print(f"{func.__name__},(a={a}, b={b}) -> {r})
return r
return wrapper
@trace
def add(a,b):
return a+b
클래스를 만들면서 메서드에 데코레이터를 사용할 때는 self를 주의해야합니다. 인스턴스 메서드는 항상 self를 받으므로 데코레이터를 만들 때도 wrapper함수의 첫 번째 매개변수는 self로 지정해야합니다. 마찬가지로 func를 호출할 때도 self와 매개 변수를 그대로 넣어야합니다.
가변 인수 함수 데코레이터
def trace(func):
def wrapper(*args, **kwargs):
r = func(*args, **kwargs)
print(f"{func.__name__},(args={args}, kwargs={kwargs}) -> {r})
return r
return wrapper
@trace
def get_max(*args):
return max(args)
@trace
def get_min(**kargs):
return min(kwargs.values())
get_max(10, 20)
get_min('x'=10, 'y'=20)
매개변수가 있는 데코레이터 만들기
def is_multiple(x): # 데코레이터가 사용할 매개변수를 지정
def real_decorator(func): # 호출할 함수를 매개변수로 받음
def wrapper(a, b): # 호출할 함수의 매개변수와 똑같이 지정
r = func(a, b) # func를 호출하고 반환값을 변수에 저장
if r % x == 0: # func의 반환값이 x의 배수인지 확인
print('{0}의 반환값은 {1}의 배수입니다.'.format(func.__name__, x))
else:
print('{0}의 반환값은 {1}의 배수가 아닙니다.'.format(func.__name__, x))
return r # func의 반환값을 반환
return wrapper # wrapper 함수 반환
return real_decorator # real_decorator 함수 반환
@is_multiple(3) # @데코레이터(인수)
def add(a, b):
return a + b
print(add(10, 20))
print(add(2, 5))
매개변수가 있는 데코레이터를 여러 개 지정할 수 있습니다.
@데코레이터1(인수)
@데코레이터2(인수)
def 함수이름(인수):
코드
함수이름(인수)
def 함수이름(인수):
코드
데코레이터1(인수)(데코레이터2(인수)함수이름)(인수)
클래스로 데코레이터 만들기
클래스로 데코레이터를 만들때는 인스턴스를 함수처럼 호추라게 해주는 __call__
메서드를 구현해야합니다. 다음은 함수의 시작과 끝을 출력하는 데코레이터입니다.
class Trace:
def __init__(self, func):
self.func = func
def __call__(self):
print(self.func.__name__, '함수 시작')
self.func()
print(self.func.__name__, '함수 끝')
@Trace
def hello():
print('hello')
hello()
# 데코레이터 @으로 지정하지 않고 호출하는 방법
def hello():
print('hello')
trace_hello = Trace(hello)
trace_hello() #
클래스로 매개변수와 반환값을 처리하는 데코레이터 만들기
class Trace:
def __init__(self, func): # 호출할 함수를 인스턴스의 초깃값으로 받음
self.func = func # 호출할 함수를 속성 func에 저장
def __call__(self, *args, **kwargs): # 호출할 함수의 매개변수를 처리
r = self.func(*args, **kwargs) # self.func에 매개변수를 넣어서 호출하고 반환값을 변수에 저장
print('{0}(args={1}, kwargs={2}) -> {3}'.format(self.func.__name__, args, kwargs, r))
# 매개변수와 반환값 출력
return r # self.func의 반환값을 반환
@Trace # @데코레이터
def add(a, b):
return a + b
print(add(10, 20))
print(add(a=10, b=20))
클래스로 매개변수가 있는 데코레이터 만들기
class IsMultiple:
def __init__(self, x): # 데코레이터가 사용할 매개변수를 초깃값으로 받음
self.x = x # 매개변수를 속성 x에 저장
def __call__(self, func): # 호출할 함수를 매개변수로 받음
def wrapper(a, b): # 호출할 함수의 매개변수와 똑같이 지정(가변 인수로 작성해도 됨)
r = func(a, b) # func를 호출하고 반환값을 변수에 저장
if r % self.x == 0: # func의 반환값이 self.x의 배수인지 확인
print('{0}의 반환값은 {1}의 배수입니다.'.format(func.__name__, self.x))
else:
print('{0}의 반환값은 {1}의 배수가 아닙니다.'.format(func.__name__, self.x))
return r # func의 반환값을 반환
return wrapper # wrapper 함수 반환
@IsMultiple(3) # 데코레이터(인수)
def add(a, b):
return a + b
print(add(10, 20))
print(add(2, 5))