이펙티브 파이썬 Item 26. functools.wrap을 사용해 함수 데코레이터를 정의하라

    요약

    • 데코레이터를 사용했을 때, 데코레이터 함수는 원본 함수의 정보와 Docs에 대한 정보를 더 이상 반환하지 않는다.
    • 데코레이터를 이렇게 사용하면 디버깅 하는 과정에서 잘못 동작할 수 있다.
    • 이런 부분을 해결하기 위해 functools의 wraps 데코레이터를 사용해주면 된다. 

     


    Item 26. functools.wrap을 사용해 함수 데코레이터를 정의하라

    # 데코레이터를 사용하면, 기존 함수의 이름과 __Docs__는 없어짐. 
    # 디버깅 시에 문제가 발생할 수 있음.
    def deco(func):
        def wrapper_func(*args, **kwargs):
            print('here')
            return func(*args, **kwargs)
        return wrapper_func
    
    
    @deco
    def hello():
        print('hello')
        return 1
    
    print(hello.__name__)
    >>>
    wrapper_func

    데코레이터는 함수의 문맥을 강화하거나, 도우미 함수를 추가해서 AOP를 손쉽게 구현할 수 있도록 도와주는 기능이다. 그렇지만 한가지 문제점이 있다. 별다른 것들을 추가하지 않는다면 데코레이터 함수는 '기존 함수의 정보'를 전혀 반환하지 않는다는 것이다. 위 코드에서는 다음 정보가 없어진다.

    • hello() 함수의 이름은 더 이상 hello가 아니라 wrapper_func가 된다.
    • hello() 함수에 작성된 docs는 이제 없어진다. 

    이런 것들은 디버깅을 하는 시점에 잘못된 정보가 전달되어서 혼란을 가중시킨다. 그렇다면 기존 함수의 이름, DOCS를 유지하는 방법은 없을까? 

    import functools
    
    # 데코레이터를 사용하더라도 기존 함수의 이름, doc이 잘 전달될 수 있도록
    # 다음 명령어를 사용하자.
    
    def deco(func):
        @functools.wraps(func)
        def wrapper_func(*args, **kwargs):
            print('here')
            return func(*args, **kwargs)
        return wrapper_func
    
    
    @deco
    def hello():
        print('hello')
        return 1
    
    print(hello.__name__)
    >>>
    hello

    이를 위해서 functools 라이브러리가 제공되고, 여기서 wraps() 데코레이터를 사용하면 된다.

    • @functools.wraps()를 사용하면 기존 함수의 이름과 문서를 그대로 유지할 수 있게 된다. 
    • 기존에는 hello_..name__을 출력했을 때 wrapper_func 라는 이름이 나왔었는데, 지금은 hello가 나오는 것을 볼 수 있다.

    댓글

    Designed by JB FACTORY