안녕하세요!

python decorator(데코레이터) 간단 정리 본문

개발일지/python

python decorator(데코레이터) 간단 정리

shinyfood 2023. 11. 15. 23:13
728x90
반응형

데코레이터는 마치 마트료시카 같다.

데코레이터(Decorator)

  • 함수의 재사용성을 확장한 개념 방법

데코레이터의 개념을 이해하기위해선, 파이썬에서의 first class 함수, closure함수를 알아야한다.

* first class function : 함수 자체를 argument로 다른 함수에 전달 또는 다른 함수의 결과값으로 return 할 수도 있고, 함수를 변수에 할당, 데이터 구조안에 저장할 수 있는 함수를 뜻한다.

 

함수 실행시간을 확인하는 데코레이터 프로그램을 한번 만들어보도록 하자.

 

우선 시간을 확인하려면 time을 import 해야한다.

import time
def timer_decorator(func) :
    def wrapper(*args, **kwargs) :
        start_time = time.time()
        
        rs = func(*args, **kwargs)
        
        end_time = time.time()
        
        return rs
    return wrapper
    
@timer_decorator
def exe_function() : 
    print("실제 처리할 함수")
    time.sleep(2)
# 2초 대기 : 데코레이터가 처리되는 시간을 잠시 주기 위함.

클로져 함수와 많이 닮아있다. 함수 내부의 함수가 있지만 @timer_decorator에 있는 exe_function()이 데코레이터의func자리에 들어가서 작동하기 때문에, 실제적으로는 내부함수가 작동한다.

 

exe_function()

start_time = 1699930636.5838223
실제 처리할 함수
end_time = 1699930638.5855138

해당하는 함수에서는 중간에 rs 라는 값이 function을 한번 실행시켰기 때문에, 실제 처리할 함수 라는게 같이 프린트되어 등장했다. start와 end time은 unix time으로 변환되어 표시됐다. 거의 2초간격으로 나온것을 볼 수 있다.

(한국시간으로는 Tue Nov 14 2023 11:57:18 이다)

 

데코레이터 함수를 배울 때 이해가 잘 되지 않았다.

간단히 생각하면 저기로 들어간다 하고 마는건데, 왜 들어가는건지 어떻게 들어가는건지가 궁금했다.

 메모리의 주소값이 기존에 timer_decorator이 가리키는자리와, wrapper가 가리키는 주소exe_function이 가리키는 주소는 각각 다르지만, 함수가 실행되면서 decorator인 exe_function이 func 자리에 들어가면서 wrapper 와 같은 메모리 주소를 갖게 되고, 같은 메모리 주소를 가졌기 때문에 exe_function을 실행 했을때, 내부함수가 작동하는 방식이다. 

 

 

추가로 데코레이 내부함에서 처리된 결과를 받아보는 함수를 보도록 하자.

def check_permission(param_id) :

    def decorator(func) :
        
        def wrapper(*args, **kwargs) :
            check_id = "admin"
            
            if check_id == param_id :
                args = ["인증성공"]
                
                return func(*args, **kwargs)
            
            else :
            
                ## raise = 강제로오류발생 permissionError 를 발생시키겠습니다
                raise permissionError("접근 불가!!")

        return wrapper

    return decorator
    
@check_permission(param_id = "admin")
def admin_function(rs_msg) :
admin_function()

인증결과 : 인증성공

복잡해보이지만, 결국은 데코레이터가 func로 들어가며 최상위함수기준으로 내부의 내부함수를 작동시키는 주소를 가지고, 파라미터를 전달해서 인증성공으로 결과가 리턴되는것을 볼 수 있다.

 

2개의 대문자를 넣었을때, 2개의 소문자로 변환되어 나오는 데코레이터를 만들어보도록 하자.

def decorator_upper(func) :

    def wrapper(*args, **kwargs) :

        args = [arg.lower() for arg in args]
        
        return func(*args, **kwargs)
    return wrapper
    
@decorator_upper
def getUpper(param1, param2) :
getUpper("A","B")

변환결과 : a / b

 

데코레이터 함수를 사용하는 이유는, 기존의 함수가 계속해서 메모리에 올라가있는 방식으로 작동하므로, 내부함수를 이용하여 결과값만 얻어내고 함수자체는 메모리에서 없애버리는 역할을하여 최적화가 되고, 함수를 숨겨주는 역할을 할 수 있기 때문이다. 

 이 점을 인지하고 사용하기 바란다!

728x90
반응형