https://dojang.io/mod/page/view.php?id=2427
파이썬 코딩 도장: 42.1 데코레이터 만들기
Unit 42. 데코레이터 사용하기 파이썬은 데코레이터(decorator)라는 기능을 제공합니다. 데코레이터는 장식하다, 꾸미다라는 뜻의 decorate에 er(or)을 붙인 말인데 장식하는 도구 정도로 설명할 수 있습
dojang.io
클로저 사용법 : https://fiasco-at-python.tistory.com/46
0. 데커레이터 도입 개념
# 함수 출력 결과 확인
def hello():
print('hello 함수 시작')
print('hello')
print('hello 함수 끝')
def world():
print('world 함수 시작')
print('world')
print('world 함수 끝')
hello()
world()
# closure를 이용한 함수 호출
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() # 반환된 함수를 호출
1. 데커레이터
# 데커레이터 원리
def trace(func): # 호출할 함수를 매개변수로 받음
def wrapper(): # 호출할 함수를 감싸는 함수
print(func.__name__, '함수 시작') # __name__으로 함수 이름 출력
func() # 매개변수로 받은 함수를 호출
print(func.__name__, '함수 끝')
return wrapper # wrapper 함수 반환
@trace
def hello():
print('hello')
hello()
1.1 함수 데커레이터
# 여러개의 데코레이터 지정
def decorator1(func):
def wrapper():
print('decorator1')
func()
return wrapper
def decorator2(func):
def wrapper():
print('decorator2')
func()
return wrapper
@decorator1
@decorator2
def hello():
print('hello')
hello()
# 데커리터 미사용시 위와 동일
def hello():
print('hello')
result=decorator1(decorator2(hello))
result()
# 매개변수와 반환값을 출력하는 데코레이터
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))
# 데커레이터 미사용
def add(a, b): # 매개변수는 두 개
return a + b # 매개변수 두 개를 더해서 반환
result = trace(add)
print(result(10,20))
# 가변 인수 함수 데코레이터
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,**kwargs):
result1 = max(args)
result2 = max(kwargs.values())
result = max(result1,result2)
return result
print(get_max(10, 20,30,a=15))
# 메서드에 데코레이터 사용하기
클래스를 만들면서 메서드에 데코레이터를 사용할 때는 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
return wrapper
class Calc:
@trace
def add(self, a, b): # add는 인스턴스 메서드
return a + b
c = Calc()
print(c.add(10, 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))
# 매개변수가 있는 데코레이터를 여러 개 지정하기
import functools
def is_multiple(x):
def real_decorator(func):
@functools.wraps(func) # @functools.wraps에 func를 넣은 뒤 wrapper 함수 위에 지정
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
add(10, 20)
'''
# 동일 결과
decorated_add = is_multiple(3)(is_multiple(7)(add))
decorated_add(10, 20)
''''
1.2 클래스 데커레이터
# class 콜러를 이용한 데커레이터
# 클래스에 __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() # 함수를 그대로 호출
# 데커레이터 미사용 시
def hello():
print('hello')
trace_hello = Trace(hello) # 데코레이터에 호출할 함수를 넣어서 인스턴스 생성
trace_hello() # 인스턴스를 호출. __call__ 메서드가 호출됨
# 매개변수와 반환값을 처리하는 클래스로 만든 데코레이터
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))
'Python Basic' 카테고리의 다른 글
이터레이터(iterator) (0) | 2022.11.23 |
---|---|
Exception (0) | 2022.11.23 |
closure 사용법 (0) | 2022.11.23 |
Programming productivity tools (0) | 2022.11.08 |
Debugging (0) | 2022.11.08 |