[짤막] Decorator

Jeong SeongYun·2022년 8월 14일
0

짤막

목록 보기
11/16
post-thumbnail

우리가 개발한 딥러닝 모델을 배포하려면 보통 python의 flask를 주로 사용합니다.

아직 해본 적은 없지만 flask나 django 이용한 모델 배포도 제가 보기엔 꼭 필수적인 부분 같아서 이 부분은 무조건 공부해보고 꼭 정리해서 포스팅할 예정입니다.

어쨌든 flask에서 주로 사용되는 python 문법이 바로 데코레이터(Decorator)입니다.

함수나 class 위에 @{name} 이런 식으로 되어 있는 경우 종종 본 적 있죠? 그게 바로 데코레이터입니다.

뭐 일단 한번 보도록 하죠!

알아둬야 하는 용어들

First-class object (1급 객체)

변수나 데이터 구조에 할당이 가능한 객체를 의미합니다. 객체가 있으면 그걸 변수에 담아낼 수 있는 녀석들을 말하죠. 파이썬의 모든 함수들은 First-class object로서 parameter나 return 값으로 활용 가능합니다.

무슨 말인지 복잡하죠? 그냥 아래처럼 사용가능하다는 말입니다.

변수에 담아내는 경우

def plus_one (x) :
    return x+1

f = plus_one

f(5)

Output
6

plus_one이라는 함수를 f 라고 하는 변수에 할당 시켰습니다.

Parameter로 활용하는 경우

def being_parameter(x) :
    return x+1 

lst = [1,2,3,4,5]

list(map(being_parameter, lst))

Output
[2, 3, 4, 5, 6]

map이라고 하는 함수에 Parameter로서 들어갔습니다.

예시를 보니까 별 거 아니죠? 말만 어렵지 그걸 표현한 실제는 그렇게 어렵지는 않습니다.

Inner Function

함수 내에 존재하는 또다른 함수를 말합니다. 진짜 문자 그대로 함수 내에 새로 함수를 정의할 수 있습니다.

def big_function (x) :
    def inner_function_square(x) :
        return print(x**2)
    inner_function_square(x)
    
big_function(5)

Output
25

호출은 big_function을 했는데 함수 안에 정의한 inner_function_square()라는 함수의 기능이 발현된 것을 확인하실 수 있습니다.

진짜 별 거 아니죠?

그러나 나중 가면 되게 많이 쓰는 구조이기 때문에 이런 형식엔 익숙해지는 것이 좋습니다.

여기서 return을 함수로 지정하면 그걸 closer 라고 하죠.

Decorator

Decorator는 위와 같이 복잡해질 수 있는 closer를 간단하게 만들어주는 기능입니다.

위에서 기존의 함수에 다른 함수의 기능을 불러올 수 있다는 점을 이용하여 함수를 특별히 수정하지 않은 상태에서 추가적인 기능을 구현해낼 수 있는 것이죠.

def decorator (function) : ## 함수를 객체로 받는다! (First-class Object)
    def wrapper() : ## parameter로 들어온 객체를 감싸주는 wrapper 함수 를 집어 넣는다
                    ## 새로운 기능이 추가될 내용을 적으면 된다.
        print(function.__name__ , '함수 시작')
        function() ## wrapper 내에서 함수 호출
        print(function.__name__ , '함수 끝')
        
    return wrapper ## decorator 함수는 결국 내부 함수인 wrapper의 결과를 return

def my_name() :
    print('안녕하세요!!!!')
    
objected_my_name = decorator(my_name) ## 함수를 객체화 (First-class Object)
objected_my_name()

Output
my_name 함수 시작
안녕하세요!!!!
my_name 함수 끝

위의 함수의 순서를 말씀드리면 아래와 같습니다.
1. decorator(function) 함수가 정의된다.
2. my_name() 함수가 정의된다.
3. 정의된 decorator 함수에 정으된 my_name 함수가 parameter로 들어간 객체 objected_my_name 이 정의된다.
4. objected_my_name에 값을 할당하기 위해 함수 decorator가 호출 된다.

------ decorator 내부에서 발생하는 일 ------
5. decorator 내부의 함수 wrapper 함수가 정의된다. 동시에 wrapper 함수가 decorator의 return 값으로 나오게 된다.
6. 이 때, 아직 wrapper 함수 내부의 명령들은 시행되지 않는다.
-----------------------------------------

  1. objected_my_name()이 호출되면 이제 decorator의 내부 함수인 wrapper 함수가 시행된다.
  2. 아래의 명령들이 시행된다.
        print(function.__name__ , '함수 시작')
        function() ## wrapper 내에서 함수 호출
        print(function.__name__ , '함수 끝')
  1. 그 결과로 output으로 나온 값들이 print된다.
  2. decorator 함수는 wrapper 함수를 return 한다.
  3. 결과적으로, objected_my_name()을 호출하면 호출된 decorator 함수로 어느 정도 수정된(꾸며진) my_name 함수가 출력 되는 것이다.

엄청 복잡한 과정을 통해 기존의 my_name 함수를 수정하지 않아도 decorator 함수로 출력 값을 어느 정도 수정할 수 있었습니다.

이렇게 복잡한 일은 Python에서 절대 두 눈 뜨고 가만히 놔둘리가 없습니다. 더 간단하게 함수에 객체 할당이 가능하도록 @decorator 기능을 제공합니다.

def decorator (function) : 
    def wrapper() : 
        print(function.__name__ , '함수 시작')
        function() 
        print(function.__name__ , '함수 끝')
        
    return wrapper 

@decorator
def my_name() :
    print('안녕하세요!!!!')
    
my_name()

Output
my_name 함수 시작
안녕하세요!!!!
my_name 함수 끝

이제 굳이 함수 안에 함수를 parameter로 지정하지 않아도 @ 한방으로 간단하게 똑같은 기능을 구현이 가능해졌습니다.

이를 조금 응용하면 Decorator 2개를 동시에 활용하는 것도 가능합니다. 적용되는 순서는 위에서 아래입니다.

def decorator1 (function) : ## 함수를 객체로 받는다! (First-class Object)
    def wrapper() : ## parameter로 들어온 객체를 감싸주는 wrapper 함수 를 집어 넣는다
                    ## 새로운 기능이 추가될 내용을 적으면 된다.
        print('이건 첫번째 Decorator')
        function() ## wrapper 내에서 함수 호출
        print('이건 첫번째 Decorator')
        
    return wrapper ## decorator 함수는 결국 내부 함수인 wrapper의 결과를 return

def decorator2 (function) :
    def wrapper() :
        print('이건 두번째 Decorator')
        function()
        print('이건 두번째 Decorator')
        
    return wrapper

@decorator1
@decorator2
def my_name() :
    print('안녕하세요!!!!')
    
my_name()

Output
이건 첫번째 Decorator
이건 두번째 Decorator
안녕하세요!!!!
이건 두번째 Decorator
이건 첫번째 Decorator

이제 함수 위에 @ 하나 붙었다고 쫄 필요 없겠죠? ㅎㅎ

profile
물어보면 대답해줄 수 있는 데이터쟁이

0개의 댓글