ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python] Decorator
    개발 2024. 5. 17. 10:45

    파이썬에선 함수위에 데코레이터를 둬서 함수의 실행전후에 특정한 작업을 주입할 수 있다. 아래 코드에선 foo 함수에 logging 이란 데코레이터를 추가했고 실행 전에 before 실행 후엔 after 를 출력하도록 했다. 

     

    def logging(func):
        def wrapper(*args, **kwargs):
            print("before")
            ret = func(*args, **kwargs)
            print("after")
            return ret
    
        return wrapper
    
    @logging
    def foo():
        print("foo")
    
    foo()
    

     

     

    실행 결과 의도했던 대로 출력된다. 로깅이나 실행 전후에 처리하고 싶은 로직을 넣어야하는 경우 유용하게 사용할 수 있다.

     

    before
    foo
    after
    

     

     

    그런데 데코레이터를 사용할때 주의할 점이 있다. 아래 코드를 실행하면 어떤 결과가 나올까?

     

    def logging(func):
        def logs(*args, **kwargs):
            return func(*args, **kwargs)
    
        return logs
    
    @logging
    def foo(x):
        return x + 100
    
    print(foo.__name__)

     

    애초 우리가 의도한건 foo 의 함수 객체의 이름이므로 foo 가 출력돼야 한다. 그런데 결과 값은 데코레이터의 wrapper 함수인 logs 가 출력된다. 데코레이터 wrapper 함수를 사용하면서 기존 foo 함수의 __name__ 과 __doc__ 같은 정보가 덮어썼기 때문이다.

     

    logs
    

     

     

    파이썬의 functools 라는 라이브러리에서는 데코레이터의 이런 문제점을 보완하고자 functions.wraps 라는 함수를 제공한다. 데코레이터를 쌩으로 쓰지 않고 functions.wraps 를 사용하면 기존 함수의 정보가 보존된다.

     

    from functools import wraps
    
    def logging_wrapped(func):
        @wraps(func)
        def logs(*args, **kwargs):
            print(func.__name__ + " was called")
            return func(*args, **kwargs)
        return logs
        
    @logging_wrapped
    def foo_wrapped(x):
        return x + 100
        
    print(foo_wrapped.__name__) # foo_wrapped    
    

    댓글

Designed by Tistory.