[Python] 데코레이터(Decorator) 1 - 데코레이터, 중첩 데코레이터
파이썬에서 데코레이터란 무엇인지, 그 동작에 대해 알아본다.
먼저 그에 앞서 파이썬의 클로저(Closure)의 개념을 이해하면 더 수월하게 이해할 수 있다. 관련해서는 클로저를 다룬 글을 참고하면 된다
https://comgu.tistory.com/entry/Python-클로저Closure-함수
[Python] 클로저(Closure) 함수
파이선에서 클로저 함수란 무엇인지, 그 동작에 대해 알아본다. 또한 클로저와 데코레이터의 관계도 파악한다. 클로저 (Closure)클로저란, 함수 안에서 정의된 내부 함수가 외부 함수의 지역 변수
comgu.tistory.com
데코레이터(Decorator)
데코레이터는 함수나 메서드의 동작을 동적으로 확장하거나 수정할 수 있는 강력한 도구이다. 주로 코드 재사용성, 가독성, 유지보수를 개선하기 위해 사용된다.
데코레이터는 다른 함수를 인수로 받아 새로운 함수를 반환하는 함수이며, @ 기호를 사용해서 함수의 정의 위에 적용된다.
def decorator(func):
def wrapper(*args, **kwargs):
print("함수 호출 이전")
result = func(*args, **kwargs)
print("함수 호출 이후")
return result
return wrapper
@decorator
def hello():
print("Hello, world!")
hello()
함수 호출 이전
Hello, world!
함수 호출 이후
데코레이터를 사용하지 않은 경우, hello 함수의 호출은 다음과 같이 나타내야 한다. (즉 데코레이터를 쓴다는 것은 실제로는 아래의 방식대로 함수 호출이 된다는 의미이다.)
def hello():
print("Hello, world!")
decorator(hello)()
decorator(hello)는 decorator 내부의 wrapper 함수를 의미한다. wrapper 함수는 상위의 decorator 함수의 scope에 있는 func 함수(즉 hello)를 참조하고 있는 상태이다. 그래서 wrapper 함수가 실행될 때, wrapper가 감싸고 있는 func(즉 hello) 함수가 호출될 수 있는 것이다.
데코레이터 내부의 wrapper 함수는 원 함수와 동일한 형식의 파라미터를 받아야 한다. 그렇지 않으면 데코레이터가 원래 함수에 제대로 적용되지 않을 수 있다.
보통 데코레이터의 wrapper 함수는 *args와 **kwargs를 사용하여 원 함수의 파라미터를 모두 받아 처리한다. 이렇게 하면 원 함수가 어떤 파라미터를 받든지 유연하게 대응할 수 있다.
def my_decorator(func):
def wrapper(*args, **kwargs): # 원 함수의 파라미터를 그대로 받음
print("함수 호출 이전")
result = func(*args, **kwargs)
print("함수 호출 이후")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("world")
함수 호출 이전
Hello, world!
함수 호출 이후
위 코드에서 wrapper 함수는 *args, **kwargs를 사용하여 say_hello 함수의 인자 name을 그대로 받을 수 있다.이 방식으로 데코레이터는 원 함수의 시그니처에 맞춰 유연하게 작동할 수 있다.
중첩(다중) 데코레이터
여러 데코레이터를 동시에 적용할 수도 있다.
아래는 3중 데코레이터를 적용한 예시이다.
def decorator1(func):
def wrapper(*args, **kwargs):
print("Decorator 1")
return func(*args, **kwargs)
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print("Decorator 2")
return func(*args, **kwargs)
return wrapper
def decorator3(func):
def wrapper(*args, **kwargs):
print("Decorator 3")
return func(*args, **kwargs)
return wrapper
@decorator1
@decorator2
@decorator3
def my_function():
print("Original function")
my_function()
Decorator 1
Decorator 2
Decorator 3
Original function
함수 정의에 가까운 데코레이터부터의 순서대로 적용된다. 첫번째 데코레이터는 원 함수의 호출을 감싸게 되고, 그 다음부터의 데코레이터는 이전 데코레이터에 의해 반환된 결과를 감싸게(wrap) 된다.
즉 데코레이터를 사용하지 않은 경우, my_function의 호출은 다음과 같이 나타내야 한다:
decorator1(decorator2(decorator3(my_function)))()
다음 글에서는 동적 데코레이터와 클래스 데코레이터에 대해 다뤄보고자 한다.
https://comgu.tistory.com/entry/Python-데코레이터Decorator-2-동적-데코레이터
[Python] 데코레이터(Decorator) 2 - 동적 데코레이터
https://comgu.tistory.com/entry/Python-데코레이터Decorator-1-데코레이터-중첩-데코레이터위 글에 이어서 데코레이터에 대한 개념을 더 정리하고자, 동적 데코레이터에 대해 다뤄보겠다. 동적 데코레이터
comgu.tistory.com