728x90
반응형
42. 데코레이터
함수를 장식하는 @staticmethod, @classmethod, @abstractmethod 등을 의미한다.
42.1 데코레이터 만들기
# 기존 방식대로 하는 경우 동일한 코드가 반복된다
def hello():
print('hello method start')
print('hello')
print('hello end')
def world():
print('world method start')
print('world')
print('world end')
hello()
world()
==========================
hello method start
hello
hello end
world method start
world
world end
def trace(func): # 호출할 함수를 매개변수로 받음
def wrapper(): # 호출할 함수를 감싸는 함수
print(func.__name__, 'method start') # __name__으로 함수 이름 출력
func() # 매개변수로 받은 함수를 출력
print(func.__name__, 'method end')
return wrapper # wrapper 함수 반환
def hello():
print('hello')
def world():
print('world')
trace_hello = trace(hello) # 데코레이터에 호출할 함수를 넣음
trace_hello() # 반환된 함수를 호출
trace_world = trace(world) # 데코레이터에 호출할 함수를 넣음
trace_world() # 반환된 함수를 호출
==========================
hello method start
hello
hello method end
world method start
world
world method end
# @으로 데코레이터 사용
def trace(func):
def wrapper():
print(func.__name__, 'method start')
func()
print(func.__name__, 'method end')
return wrapper
@trace
def hello():
print('hello')
@trace
def world():
print('world')
hello()
world()
==========================
hello method start
hello
hello method end
world method start
world
world method end
42.2 매개변수와 반환값을 처리하는 데코레이터 만들기
def trace(func): # 호출할 함수를 매개변수로 받음
def wrapper(a, b): # 호출할 함수 add(a, b)의 매개변수와 똑같이 지정
r = func(a, b) # func에 매개변수 a, b를 넣어서 호출하라고 반환값을 변수에 저장
print('{0}(a={1}, b={2}) -> {3}'.format(func.__name__, a, b, r))
# 매개변수와 반환값 출력
return r # func의 반환값을 반환
return wrapper # wrapper 함수 반환
@trace # @데코레이터
def add(a, b): # 매개변수는 두 개
return a + b # 매개변수 두 개를 더해서 반환
print(add(10, 20))
==========================
add(a=10, b=20) -> 30
30
# 가변 인수 함수 데코레이터
def trace(func):
def wrapper(*args, **kwargs):
r = func(*args, **kwargs)
print('{0}(args={1}, kwargs={2}) -> {3}'.format(func.__name__, args, kwargs, r))
return r
return wrapper
@trace
def get_max(*args):
return max(args)
@trace
def get_min(**kwargs):
return min(kwargs.values())
print(get_max(10, 20))
print(get_min(x=10, y=20, z=30))
==========================
get_max(args=(10, 20), kwargs={}) -> 20
20
get_min(args=(), kwargs={'x': 10, 'y': 20, 'z': 30}) -> 10
10
# 메서드에 데코레이터 사용하기
def trace(func):
def wrapper(self, a, b): # 호출할 함수가 인스턴스 메서드이므로
r = func(self, a, b) # 첫 번째 매개변수는 self로 지정
# self와 매개변수를 그대로 넣어줌
print('{0}(a={1}, b={2}) -> {3}'.format(func.__name__, a, b, r))
# 매개변수와 반환값 출력
return r # func의 반환값을 반환
return wrapper
class Calc:
@trace
def add(self, a, b):
return a + b
c = Calc()
print(c.add(10, 20))
==========================
add(a=10, b=20) -> 30
30
42.3 매개변수가 있는 데코레이터
def is_multiple(x):
def real_decorator(func):
def wrapper(a, b):
r = func(a, b)
if r % x == 0:
print('{0}의 반환값은 {1}의 배수'.format(func.__name__, x))
else:
print('{0}의 반환값은 {1}의 배수가 아니다'.format(func.__name__, x))
return r
return wrapper
return real_decorator
@is_multiple(3)
@is_multiple(7)
def add(a, b):
return a + b
print(add(10, 20))
print(add(2, 5))
==========================
add의 반환값은 7의 배수가 아니다
wrapper의 반환값은 3의 배수
30
add의 반환값은 7의 배수
wrapper의 반환값은 3의 배수가 아니다
7
42.4 클래스로 데코레이터
class Trace:
def __init__(self, func): # 호출할 함수를 인스턴스의 초깃값으로 받음
self.func = func # 호출할 함수를 속성 func에 저장
def __call__(self):
print(self.func.__name__, 'method start') # __name__으로 함수 이름 출력
self.func() # 속성 func에 저장된 함수 호출
print(self.func.__name__, 'method end')
@Trace
def hello():
print('hello')
hello()
==========================
hello method start
hello
hello method end
42.5 클래스로 매개변수와 반환값을 처리하는 데코레이터
class Trace:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
r = self.func(*args, **kwargs)
print('{0}(args={1}, kwargs={2}) -> {3}'.format(self.func.__name__, args, kwargs, r))
return r
@Trace
def add(a, b):
return a + b
print(add(10, 20))
print(add(a=10, b=20))
==========================
add(args=(10, 20), kwargs={}) -> 30
30
add(args=(), kwargs={'a': 10, 'b': 20}) -> 30
30
# 클래스로 매개변수가 있는 데코레이터 만들기
class IsMultiple:
def __init__(self, x):
self.x = x
def __call__(self, func):
def wrapper(a, b):
r = func(a, b)
if r % self.x == 0:
print('{0}의 반환값은 {1}의 배수'.format(func.__name__, self.x))
else:
print('{0}의 반환값은 {1}의 배수가 아니다.'.format(func.__name__, self.x))
return r
return wrapper
@IsMultiple(3)
def add(a, b):
return a + b
print(add(10, 20))
print(add(2, 5))
==========================
add의 반환값은 3의 배수
30
add의 반환값은 3의 배수가 아니다.
7
728x90
반응형
'Language > Python' 카테고리의 다른 글
[코딩도장]44. 모듈과 패키지 사용 (0) | 2022.04.19 |
---|---|
[코딩도장]43.정규표현식 (0) | 2022.04.14 |
[코딩도장]41.코루틴 (0) | 2022.04.11 |
[코딩도장]40.제너레이터 (0) | 2022.04.06 |
[코딩도장]39. 이터레이터 (0) | 2022.04.05 |