일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- nlp
- 코드오류
- 비모수적 모델
- TeCNO
- PYTHON
- precision #정밀도 #민감도 #sensitivity #특이도 #specifisity #F1 score #dice score #confusion matrix #recall #PR-AUC #ROC-AUC #PR curve #ROC curve #NPV #PPV
- tabular
- 모수적 모델
- 데코레이터
- deep learning #segmentation #sementic #pytorch #UNETR #transformer #UNET #3D #3D medical image
- 파이썬
- non-parametric model
- decorater
- nfiti
- words encoding
- parrec
- MRI
- monai
- 유전역학
- nibabel
- 확산텐서영상
- MICCAI
- 확산강조영상
- genetic epidemiology
- parametric model
- paper review
- Surgical video analysis
- Phase recognition
- TabNet
- parer review
- Today
- Total
KimbgAI
[python] 데코레이터(decorator, @)란? 본문
데코레이터란?
파이썬은 데코레이터(decorator)라는 기능은 제공하는데, 함수(매서드) 클래스를 장식하는 도구를 뜻합니다.
데코레이터는 함수를 수정하지 않은 상태에서 추가 기능을 구현할 때 사용합니다.
보통 데코레이터는 프로그램의 버그를 찾는 디버깅, 함수의 성능 측정, 함수 실행 전에 데이터 확인 등에 활용합니다.
예를 들어, 함수의 시작과 끝을 출력하고 싶다면 다음과 같이 함수 시작과 끝 부분에 print()를 넣어주면 됩니다.
def trace(func): # 호출할 함수를 매개변수로 받음
def wrapper(): # 호출할 함수를 감싸는 함수
print(func.__name__, '함수 시작') # __name__으로 함수 이름 출력
func() # 매개변수로 받은 함수를 호출
print(func.__name__, '함수 끝')
return wrapper # wrapper 함수 반환
def hello():
print('hello')
trace_hello = trace(hello) # 데코레이터에 호출할 함수를 넣음
trace_hello() # 반환된 함수를 호출
hello 함수 시작
hello
hello 함수 끝
trace의 구조를 보면 아시겠지만, 함수 안에서 함수(wrapper)를 만들고 함수 자체를 반환하는 클로저 입니다.
@로 데코레이터 사용하기
@를 사용하여 좀 더 간편하게 데코레이터를 사용할 수 있습니다.
def trace(func): # 호출할 함수를 매개변수로 받음
def wrapper():
print(func.__name__, '함수 시작') # __name__으로 함수 이름 출력
func() # 매개변수로 받은 함수를 호출
print(func.__name__, '함수 끝')
return wrapper # wrapper 함수 반환
@trace # @데코레이터
def hello():
print('hello')
hello() # 함수를 그대로 호출
hello 함수 시작
hello
hello 함수 끝
이렇게 데코레이터는 함수를 감싸는 형태로 구성되어 있습니다.
따라서 기존 함수를 수정하지 않으면서 추가 기능을 구현할 때 사용할 수 있습니다.
매개변수와 반환값을 처리하는 데코레이터 만들기
wrapper 함수에 매개변수를 넣어주면 됩니다.
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) # func에 args, kwargs를 언패킹하여 넣어줌
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
참고 | 메서드에 데코레이터 사용하기
클래스를 만들면서 메서드에 데코레이터를 사용할 때는 self를 주의해야 합니다.
인스턴스 메서드는 항상 self를 받으므로 데코레이터를 만들 때도 wrapper 함수의 첫 번째 매개변수는 self로 지정해야 합니다(클래스 메서드는 cls).
마찬가지로 func를 호출할 때도 self와 매개변수를 그대로 넣어야 합니다.
def trace(func):
def wrapper(self, a, b): # 호출할 함수가 인스턴스 메서드이므로 첫 번째 매개변수는 self로 지정
r = func(self, a, b) # 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): # add는 인스턴스 메서드
return a + b
c = Calc()
print(c.add(10, 20))
add(a=10, b=20) -> 30
30
매개변수가 있는 데코레이터 만들기
실행을 해보면 add 함수의 반환값이 3의 배수인지 아닌지 알려줍니다.
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))
add의 반환값은 3의 배수입니다.
30
add의 반환값은 3의 배수가 아닙니다.
7
클래스로 데코레이터 만들기
특히 클래스를 활용할 때는 인스턴스를 함수처럼 호출하게 해주는 __call__ 메서드를 구현해야 합니다.
class Trace:
def __init__(self, func): # 호출할 함수를 인스턴스의 초깃값으로 받음
self.func = func # 호출할 함수를 속성 func에 저장
def __call__(self):
print(self.func.__name__, '함수 시작') # __name__으로 함수 이름 출력
self.func() # 속성 func에 저장된 함수를 호출
print(self.func.__name__, '함수 끝')
@Trace # @데코레이터
def hello():
print('hello')
hello() # 함수를 그대로 호출
hello 함수 시작
hello
hello 함수 끝
클래스로 매개변수가 있는 데코레이터 만들기
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))
add의 반환값은 3의 배수입니다.
30
add의 반환값은 3의 배수가 아닙니다.
7
참고자료
https://dojang.io/mod/page/view.php?id=2427
'python' 카테고리의 다른 글
[python] ParRec 파일을 nifti 파일로 변환 (0) | 2024.01.09 |
---|---|
[python] @property 사용하기 (0) | 2023.02.06 |
tqdm 활용 with dataloader (0) | 2022.11.07 |
[python] 자주 사용하는 conda 명령어 (0) | 2022.09.28 |
[python] pip install but can't import (0) | 2022.09.16 |