[코딩도장] day28. 파이썬 데코레이터(1/2) - @데코레이터, def데코레이터
■ 들어가기
- 파이썬 코딩 도장 (남재윤/길벗). 을 공부하며 정리하는 블로그
▶ Unit42. 데코레이터 사용하기
- 42.1 데코레이터 만들기
- 42.2 매개변수와 반환값을 처리하는 데코레이터 만들기
- 42.3 매개변수가 있는 데코레이터 만들기
- 42.4 클래스로 데코레이터 만들기
- 42.5 클래스로 매개변수와 반환값을 처리하는 데코레이터 만들기
0. 들어가기
- 데코레이터(decorator) : 클래스 내 메서드를 장식하는 도구 (표기: @)
- 사용예시
class Calc :
@staticmethod # 데코레이터
def add(a, b) :
print(a + b)
>> 42.1 데코레이터 만들기 <<
- 데코레이터는 함수를 수정하지 않은 상태에서 추가 기능 구현 시 사용
- 예제 : 함수 시작, 끝을 출력하는 기능 구현
설명 : 일반적인 함수 작성 | |
소스 (function_begin_end.py) | 결과 |
def hello() : print('hello 함수 시작') print('hello') print('hello 함수 끝') def world() : print('world 함수 시작') print('world') print('world 함수 끝') hello() world() |
hello 함수 시작 hello hello 함수 끝 world 함수 시작 world world 함수 끝 |
설명 : 데코레이터를 활용한 함수 | |
소스 (decorator_closure.py) | 결과 |
def trace(func) : # 호출할 함수를 매개변수로 받음 def wrapper() : # 호출할 함수를 감싸는 함수 print(func.__name__, '함수 시작') # __name__으로 함수 이름 출력 func() # 매개변수로 받은 함수를 호출 print(func.__name__, '함수 끝') return wrapper # wrapper 함수 반환 def hello() : print('hello') def world() : print('world') trace_hello = trace(hello) # 데코레이터에 호출할 함수를 넣음 trace_hello() # 반환된 함수를 호출 trace_world = trace(world) # 데코레이터에 호출할 함수를 넣음 trace_world() # 반환된 함수를 호출 |
hello 함수 시작 hello hello 함수 끝 world 함수 시작 world world 함수 끝 |
1. @으로 데코레이터 사용하기
- 사용법
@데코레이터
def 함수이름() :
코드
소스 (decorator_closure_at_sign.py) | 결과 |
def trace(func) : # 호출할 함수를 매개변수로 받음 def wrapper() : print(func.__name__, '함수 시작') # __name__으로 함수 이름 출력 func() # 매개변수로 받은 함수를 호출 print(func.__name__, '함수 끝') return wrapper @trace # @데코레이터 def hello() : print('hello') @trace # @데코레이터 def world() : print('world') hello() # 함수를 그대로 호출 world() # 함수를 그대로 호출 |
hello 함수 시작 hello hello 함수 끝 world 함수 시작 world world 함수 끝 |
- 그러면 trace라는 함수말고 다른 이름의 함수 만들고 해당 함수 이름으로 @ 데코레이터 붙히면 어떻게 될까??
- 결론 : 된다!!!! // 데코레이터 이름의 함수를 만들고 데코레이터로 호출하면 처리 가능하구나!! 그렇지 않으면 NameError 발생!
소스 (decorator_closure_at_sign2.py) | 결과 |
def abc(func) : # 호출할 함수를 매개변수로 받음 def wrapper() : print(func.__name__, '함수 시작') # __name__으로 함수 이름 출력 func() # 매개변수로 받은 함수를 호출 print(func.__name__, '함수 끝') return wrapper @abc # @데코레이터 def hello() : print('hello') @abc # @데코레이터 def world() : print('world') hello() # 함수를 그대로 호출 world() # 함수를 그대로 호출 |
hello 함수 시작 hello hello 함수 끝 world 함수 시작 world world 함수 끝 |
>> 42.2 매개변수와 반환값을 처리하는 데코레이터 만들기 <<
- 매개변수와 반환값을 처리하는 데코레이터 확인
- 실제 호출할 함수의 매개변수와 wrapper 함수의 매개변수를 똑같이 만들어줌
소스 (decorator_param_return.py) | 결과 |
def trace(func) : def wrapper(a, b) : r = func(a, b) print('{0}(a={1}, b={2}) -> {3}'.format(func.__name__, a, b, r)) return r return wrapper @trace def add(a, b) : return a + b print(add(10, 20)) |
add(a=10, b=20) -> 30 30 |
1. 가변 인수 함수 데코레이터
- 매개변수(인수)가 고정되지 않은 함수 처리 방법은?
-> wrapper 함수를 가변 인수 함수로 만들면 된다.
소스 (decorator_variable_argument.py) | 결과 |
def trace(func) : # 호출할 함수를 매개변수로 받음 def wrapper(*args, **kwargs) : # 가변 인수 함수로 만듦 r = func(*args, **kwargs) # func에 args, kwrargs를 언패킹하여 넣어줌 print('{0}(args={1}, kwargs={2}) -> {3}'.format(func.__name__, args, kwargs, r)) # 매개변수와 반환값 출력 return r # func의 반환값을 반환 return wrapper # 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 |
- get_max, get_min 함수는 가변 인수 함수로써, get_max 함수는 튜플로, get_min 함수는 딕셔너리(key-value)로 데이터 전달
- args 는 튜플, kwargs는 딕셔너리