[python] 데코레이터 사용하기

anjiyoo·2024년 3월 20일

Python

목록 보기
40/41
post-thumbnail

1.데코레이터

  • 함수를 수정하지 않은 상태에서 추가 기능을 구현할 때 사용
  • 프로그램의 버그를 찾는 디버깅, 함수의 성능 측정, 함수 실행 전 데이터 확인 등에 사용
  • @로 시작하는 것들
def 데코레이터이름(func): # 데코레이터는 호출할 함수를 매개변수로 받음
	def wrapper():  # 호출할 함수를 감싸는 함수
    	func()  # 매개변수로 받은 함수를 호출
    return wrapper  # wrapper 함수 반환

@데코레이터  # 데코레이터 지정
def 함수이름():
	코드
class Calc:
	@staticmethod  # 데코레이터
    def add(a,b):
    	print(a+b)

1-1.데코레이터 만들기

  • 데코레이터는 함수를 수정하지 않은 상태에서 추가 기능을 구현할 대 사용
def hello():
	print('hello 함수 시작')
    print('hello')
    print('hello 함수 끝')
    
def world():
	print('world 함수 시작')
    print('world')
    print('world 함수 끝')

hello()
world()
위의 함수를 데코레이터 활용
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-2.@으로 데코레이터 사용하기

@데코레이터
def 함수이름():
	코드
def trace(func):  # 호출할 함수를 매개변수로 받음
	def wrapper():
    	print(func.__name__, '함수 시작')  # __name__으로 함수 이름 출력
        func()  # 매개변수로 받은 함수를 호출
        print(func.__name__, '함수 끝')
    return wrapper  # wrapper 함수 변환
    
@trace  # @데코레이터
def hello():
	print('hello')
   
@trace # @데코레이터
def world():
	print('world')
    
hello()  # 함수를 그대로 호출
world()  # 함수를 그대로 호출

2.매개변수와 반환값을 처리하는 데코레이터 만들기

def 데코레이터이름(func):  # 데코레이터는 호출할 함수를 매개변수로 받음
	def wrapper(매개변수1, 매개변수2):  # 호출할 함수의 매개변수와 똑같이 지정
    	return func(매개변수1, 매개변수2)  # func에 매개변수를 넣어서 호출하고 반환값을 반환
    return wrapper  # wrapper 함수 반환

@데코레이터  # 데코레이터 지정
def 함수이름(매개변수1, 매개변수2):  # 매개변수는 두 개
	코드
def trace(func):  # 호출할 함수를 매개변수로 받음
	def wrapper(a,b):  # 호출할 함수 add(a,b)의 매개변수로 똑같이 지정
    	r = func(a,b)  # func에 매개변수 a,b를 넣어서 호출하고 반환값을 변수에 저장
        print('{0}(a=1{1}, b={2}) -> {3}'.format(func.__name__, a, b, r))
        		# 매개변수와 반환값 출력
                # func의 반환값을 반환
        return r  # func의 반환값 반환
    return wrapper  # wrapper 함수 반환
    
@trace  # @데코레이터
def add(a,b):  # 매개변수는 두 개
	return a+b  # 매개변수 두 개를 더해서 반환
    
print(add(10,20))

2-1.가변 인수 함수 데코레이터

  • 매개변수의 개수가 고정된 함수
    매개변수(인수)가 고정되지 않은 함수는 wrapper 함수를 가변 인수 함수로 만들면 됨
def trace(func):  # 호출할 함수를 매개변수로 받음
	def wrapper(*args, **kwargs):  # 가변 인수 함수로 만듦
    	r = func(*args, **kwargs)  # 가변 인수 함수로 만듦
        print('{0}(args={1}, kwargs={2} -> {3}'.format(func.__name__, args, kwargs, r))		
        		# 매개변수와 반환값 출력
        		# func의 반환값을 반환
        return r  # 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))

3.매개변수가 있는 데코레이터 만들기

  • 데코레이터는 값을 지정해서 동작을 바꿀 수 있음
# 데코레이터 사용
데코레이터(인수)
def 함수이름():
	코드
def 데코레이터이름(매개변수):  # 데코레이터가 사용할 매개변수를 지정
	def real_decorator(func):  # 호출할 함수를 매개변수로 받음
    	def wrapper(매개변수1, 매개변수2):  # 호출할 함수이 매개변수와 똑같이 지정
        	return func(매개변수1, 매새변수2)  # func를 호출하고 반환값을 반환
        return wrapper  # wrapper 함수 반환
    return real_decorator  # real_decorator 함수 반환

@데코레이터(인수)  # 데코레이터를 지정하면서 인수를 넣음
def 함수이름(매개변수1, 매개변수2):
	코드
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_decoragor  # real_decorator 함수 반환

#is_multiple(3)  #@데코레이터(인수)
def add(a,b):
	return a+b

print(add(10,20))
print(add(2,5))

4.클래스로 데코레이터 만들기

  • 클래스를 활용할 때는 인스턴스를 함수처럼 호출하게 해주는 __call__메소드를 구현
class 데코레이터이름:
	def __init__(self, func):  # 호출할 함수를 인스턴싀 초깃값으로 받음
    	self.func = func  # 호출할 함수를 속성 func에 저장
    
    def __call__(self, 매개변수1, 매개변수2):  # __call__에서 호출할 함수의 매개변수 처리
    	return self.func(매개변수1, 매개변수2)  # self.func에 매개변수를 넣어서 호출하고 반환값을 반환
        
@데코레이터  # 데코레이터 지정
def 함수이름(매개변수1, 매개변수2)::
	코드
class Trace:
	def __init__(self, func):  # 호출할 함수를 인스턴스의 초깃값으로 받음
    	self.func = func  # 호출할 함수를 속성 func에 저장
        
    def __call__(self):
    	print(self.func.__name__, '함수 시작')  # __name__으로 함수 이름 출력
        self.func()
        print(self.func.__name__, '함수 끝')
        
 @Trace  # @데코레이터
 def hello():
 	print('hello')

hello()  # 함수를 그대로 호출

5.클래스로 매개변수와 반환값을 처리하는 데코레이터 만들기

  • 클래스로 매개변수와 반환값을 처리하는 데코레이터를 만들 때는 __call__메소드에 매개변수를 저장
    self.func에 매개변수를 넣어서 호출한 뒤 반환값을 반환해줌
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(slef.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))

5-1.클래스로 매개변수가 있는 데코레이터 만들기

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))         	
profile
기록으로 흔적을 남기는 것을 좋아합니다

0개의 댓글