[Fluent Python] 7장 함수 데커레이터와 클로저

7장 함수 데커레이터와 클로저

데커레이터 기본 지식

함수 위에 데커레이션을 쓰면 래핑된다. 엄밀히 말하면 편리 구문(Syntax sugar)일 뿐이지만, 런타임에 프로그램을 변경하는 메타프로그래밍에 매우 유용하다.

데커레이터가 실행되는 시점

임포트 시점에 실행된다.

데커레이터를 이용한 전략(Strategy) 패턴

앞서 best_promo()라는 기능을 구현하기 위해서 할인함수 리스트를 만들어서, 리스트를 추가하는 방식으로 이용하였다. 데코레이터를 이용하면, 할인함수에 @promotion이라고 래핑을 하고, 이 함수를 리스트에 추가하는 방식으로 구현할 수 있다. 이 경우, 함수명을 특정한 이름로 한정할 필요가 없고, 데커레이터를 쓰고/지우고 함으써, 가독성이 좋아진다. 그리고 데커레이션만 붙이면 되므로, 굳이 한 모듈에 둘 필요가 없다.

변수 범위 규칙

일반적으로 변수 범위는 생각처럼 잘 동작한다. 하지만, 함수에서 변수가 선언되면, 그 변수는 로컬 변수로 인식되어, 함수 내에서 로컬변수가 선언되기 이전에 해당 변수에 접근하는 경우, 글로벌 변수를 찾지 못한다. 이 때 global 키워드를 이용한다.

클로저

클로저는 본체에서 정의하지 않고, 참조하는 비전역(nonglobal) 변수를 포함한 함수이다. 익명함수와 혼동하는 경우가 많은데, 클로저는 익명여부와 무관하다.

클로저 안에서 선언되는 변수는 자유 변수(free variable)다.

자유변수로 쓰기 위해서 nonlocal를 이용한다. 특히 count += 1과 같은 구문을 쓰는 경우, 할당문이 포함되기 때문에 파이썬은 지역변수로 가정하게 된다. 따라서 앞서 변수 범위 규칙처럼 nonlocal 키워드를 이용하게 된다.

파이썬2에서는 nonlocal를 지원하지 않기 때문에, 가변 객체(dict나 간단한 객체 등)를 이용한다.

데커레이터의 활용 예

함수 실행시간을 측정하는 함수로 이용할 수 있다.

예제코드는 여기에서 참조할 수 있다.

표준 라이브러리에서 제공하는 데커레이터

재귀형태를 이용한 피보나치 함수를 구현하였을 때, @functolls.lru_cache()를 이용하면, 메모이제이션을 통해 간단하게 효율적으로 구현할 수 있다. lru_cache()는 재귀 알고리즘 외에도 웹에서 정보를 가져와야하는 애플리케이션에서도 이용할 수 있다.

단일 디스패치를 이용한 범용함수 (single dispatch)

@singledispatch로 기반함수를 정의하고, @<기반함수>.register(<객체형>)를 통해서 분기할 수 있다. 함수를 선택하기 위해서 한개의 인자만을 이용한다.

자바의 메서드 오버로드와 유사하지만, 이를 구현하기 위해 추가된 것은 아니다.

누적된 데커레이터

@d1
@d2
def f():
    pass

위 코드는 d1(d2(f))와 동일하다.

매개변수화된 데커레이터

데커레이터에 괄호를 이용하여 매개변수를 전달할 수 있다.

읽을거리