오늘도 데코레이터에 대한 설명이 충분치 않아 이에 대한 설명을 더 찾아보았다. 설명을 찾으려고 보니 데코레이터를 설명하기 이전에 클로저를 설명하는 글이 많았는데, 이를 찬찬히 살펴보니 데코레이터의 구현의 대부분이 클로저를 이용하여 이루어지기 때문이라고 나는 이해했다.

 

클로저에 대해 알아보기 전에 중첩함수와 자유변수를 먼저 알아보자.

  • 중첩함수란 함수 내부에서 정의된 함수를 의미하는데 함수 내부에서만 호출 가능하기 때문에 로직을 분리하거나 캡슐화를 위해 사용된다. 아래 예제에서 inner_function은 중첩함수이다.
  • 자유변수란 매개변수도, 지역변수도 아니면서 함수 외부에서 정의되었지만 함수 내부에서 사용하는 변수를 말한다. 아래 예제에서 inner_function 입장에서는 x는 자유변수다.
def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

closure = outer_function(10)
print(closure(5))  # 결과: 15

 

클로저는 이 중첩함수를 이용하여 만들어지는 기능으로, 중첩함수 inner_function 외부에서 정의되는 자유변수 x를 기억하고 유지하도록 하는 형태를 클로저라고 나는 이해했다. outer_fuction이 어떻게 되든, inner_function은 참조하는 자유 변수의 정보를 계속 유지한다.

 

클로저를 이용하여 함수를 은닉화 할수도 있으며 동적으로 생성하고 조작할 수 있다. 특히 이렇게 생성된 각 클로저들은 함수의 상태를 유지하므로 같은 클로저라 하여도 다른 정보들을 담을 수 있다는 점이 아주 유용하다고 생각된다.

 

https://shoark7.github.io/programming/python/closure-in-python

 

Python의 Closure에 대해 알아보자

Python에서 유용한 Closure에 대해 살펴봅니다.

shoark7.github.io

위 내용을 추가적으로 읽었는데, 내 설명이 깊이감 있는 설명은 아닌 것 같다. 아마 차후에 더 두텁게 수정할 것이다.

 

데코레이터는 대부분 클로저를 이용한 구현이다. 클로저의 원래 함수의 상태 유지 기능을 이용하여 원래 함수와 상태를 유지하는 것이고 또한 디자인 패턴의 데코레이터를 구현한 형태이라고 나는 이해하고 있다. 파이썬에서는 아래와 같은 형태로 사용된다.

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
    return wrapper

@my_decorator
def example_function():
    print("Inside function")

example_function()

# Before function call
# Inside function
# After function call

함수 실행 전후로 미리 만들어진 데코레이터가 작동하며 함수 위에서 @데코레이터_함수명 이라고 치는 것만으로 실행되니, 공통된 부분을 가독성 있게 만들 수 있게 됐다.

 

앞서 말했듯이 '대부분'의 데코레이터는 클로저 형태를 사용한다. 물론 아닌 것도 있으니, 바로 클래스를 이용한 형태이다. 클로저의 형태로 작성한 것이 더 간결하고 이해하기 쉽기 때문에 그냥 이런 것도 있구나 알고 있는 게 좋은 것 같다.

class MyDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("Before function call")
        result = self.func(*args, **kwargs)
        print("After function call")
        return result

@MyDecorator
def example_function():
    print("Inside function")

example_function()

# Before function call
# Inside function
# After function call

클래스 내에서 __call__ 을 정의해 만든 구현인데 결과는 클로저 때와 똑같다.

 

복사했습니다!