함수를 받아 명령을 추가한 뒤 이를 다시 함수의 형태로 반환하는 함수
함수의 내부를 수정하지 않고 기능에 변화를 주고 싶을 때 사용
함수의 전처리나 후처리에 대한 필요가 있을 때 사용
반복을 줄이고 메소드나 함수의 책임을 확장
데코레이터 사용 X
def decorator_function(original_function):
def wrapper_function():
print(f'{original_function.__name__} 함수가 호출되기 전 입니다')
return original_function()
return wrapper_function
def display_1():
print('display_1 함수가 실행됐습니다')
def display_2():
print('display_2 함수가 실행됐습니다')
display_1 = decorator_function(display_1) #1
display_2 = decorator_function(display_2) #2
display_1()
display_2()
#출력 결과
#display_1 함수가 호출되기 전 입니다
#display_1 함수가 실행됐습니다
#display_2 함수가 호출되기 전 입니다
#display_2 함수가 실행됐습니다
@<데코레이터함수이름>
쓰는 간단한 구문 사용데코레이터 사용
def decorator_function(original_function):
def wrapper_function():
print(f'{original_function.__name__} 함수가 호출되기 전 입니다')
return original_function()
return wrapper_function
@decorator_function
def display_1():
print('display_1 함수가 실행됐습니다')
@decorator_function
def display_2():
print('display_2 함수가 실행됐습니다')
display_1()
display_2()
#출력 결과
#display_1 함수가 호출되기 전 입니다
#display_1 함수가 실행됐습니다
#display_2 함수가 호출되기 전 입니다
#display_2 함수가 실행됐습니다
타입 에러 (wrapper_function은 인자를 받지 않는데 2개의 인자 전달)
def decorator_function(original_function):
def wrapper_function():
print(f'{original_function.__name__} 함수가 호출되기 전 입니다')
return original_function
return wrapper_function
@decorator_function
def display_info(name, age):
print('display (f{name, age}) 함수가 실행됐습니다')
display_info('name' , 10)
#Traceback (most recent call last):
# File "c:/Users/chldp/OneDrive/바탕 화면/파이썬/t.py", line 12, #in <module>
# display_info('name' , 10)
#TypeError: wrapper_function() takes 0 positional arguments but #2 were given
위의 타입 에러 고치기
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print(f'{original_function.__name__} 함수가 호출되기 전 입니다')
return original_function(*args, **kwargs)
return wrapper_function
@decorator_function
def display():
print('display 함수가 실행됐습니다')
@decorator_function
def display_info(name, age):
print(f'display({name}, {age}) 함수가 실행됐습니다')
display()
display_info('name' , 10)
#display 함수가 호출되기 전 입니다
#display 함수가 실행됐습니다
#display_info 함수가 호출되기 전 입니다
#display(name, 10) 함수가 실행됐습니다
클래스 형식 사용하기
클래스 형식의 데코레이터는 그다지 많이 사용되지 않고 보통 함수 형식이 많이 사용
class DecoratorClass:
def __init__(self, original_finction):
self.original_finction = original_finction
def __call__(self, *args, **kwargs):
print(f'{self.original_finction.__name__} 함수가 호출되기 전 입니다')
return self.original_finction(*args, **kwargs)
@DecoratorClass
def display():
print('display 함수가 실행됐습니다')
@DecoratorClass
def display_info(name, age):
print(f'display({name}, {age}) 함수가 실행됐습니다')
display()
display_info('name' , 10)
#display 함수가 호출되기 전 입니다
#display 함수가 실행됐습니다
#display_info 함수가 호출되기 전 입니다
#display(name, 10) 함수가 실행됐습니다
def out_func(func): #기능을 추가할 함수를 인자로
def inner_func(*args, *kwargs):
return func(*args, **kwargs)
return inner_func
decorator 역할을 하는 함수 정의하고 이 함수에서 decorator가 적용될 함수를 인자로 받는다
decorator 역할을 하는 함수 내부에 또 함수를 선언(nested function)하여 여기에 추가적인 작업을 선언
nested function을 return
예시
def decorator(func):
def wrapper(*args, **kwargs):
print('전처리')
print(func(*args, **kwargs)
return wrapper
@decorator
def exmaple():
return '함수'
example()
#전처리
#함수
#후처리
class Decorator:
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
return self.function(*args, **kwargs)
__call__
함수로 decorator 형식 정의예시
class Decorator:
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
print('전처리')
print(self.function(*args, **kwargs)
print('후처리')
@Decorator
def example():
return '클래스'
example()
#전처리
#클래스
#후처리
import datetime
import time
def my_logger(original_function):
import logging
logging.basicConfig(filename='{}.log' .format(original_function.__name__, level=logging.INFO))
def wrapper(*args, **kwargs):
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
logging.info(
'[{}] args - {}, kwargs - {}' .format(timestamp, args, kwargs))
return original_function(*args, **kwargs)
return wrapper
def my_timer(original_function):
import time
def wrapper(*args, **kwargs):
t1 = time.time()
result = original_function(*args, **kwargs)
t2 = time.time() - t1
print('{} 함수가 실행된 총 시간 {}초' .format(original_function.__name__, t2))
return result
return wrapper
@my_timer
@my_logger
def display_info(name, age):
time.sleep(1)
print(f'display_info({name}, {age}) 함수가 실행됐습니다')
display_info('name', 10)
#display_info(name, 10) 함수가 실행됐습니다
#wrapper 함수가 실행된 총 시간 1.015899896621704초
functools 모듈의 wraps 데코레이터 사용
from functools import wraps
import datetime
import time
def my_logger(original_function):
import logging
logging.basicConfig(filename='{}.log' .format(original_function.__name__, level=logging.INFO))
@wraps(original_function)
def wrapper(*args, **kwargs):
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
logging.info(
'[{}] args - {}, kwargs - {}' .format(timestamp, args, kwargs))
return original_function(*args, **kwargs)
return wrapper
def my_timer(original_function):
import time
@wraps(original_function)
def wrapper(*args, **kwargs):
t1 = time.time()
result = original_function(*args, **kwargs)
t2 = time.time() - t1
print('{} 함수가 실행된 총 시간 {}초' .format(original_function.__name__, t2))
return result
return wrapper
@my_timer
@my_logger
def display_info(name, age):
time.sleep(1)
print(f'display_info({name}, {age}) 함수가 실행됐습니다')
display_info('name', 10)
#display_info(name, 10) 함수가 실행됐습니다
#display_info 함수가 실행된 총 시간 1.0032978057861328초
참고
https://hckcksrl.medium.com/python-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-decorator-980fe8ca5276
https://bluese05.tistory.com/30
http://schoolofweb.net/blog/posts/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-decorator/