개발
[Python] Decorator
kwony
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