1. 함수가 품은 보물상자: 클로저 (Closure)
데이터뿐만 아니라 ‘함수’ 자체도 변수에 담거나 남에게 던져줄(Return) 수 있다는 사실을 아시나요? 파이썬에서 함수는 일급 시민(First-class citizen)이기 때문입니다. 데코레이터를 이해하기 위한 첫 관문은 바로 클로저(Closure) 현상입니다.
1.1 함수 안의 함수 (Nested Function)
파이썬은 함수 내부에 또 다른 함수를 만들 수 있습니다. 그리고 이 내부 함수를 외부로 반환(return)할 때 아주 재미있는 현상이 일어납니다.
def make_multiplier(n):
# n은 외부 함수의 지역 변수입니다.
def multiplier(x):
# 내부 함수에서 외부 변수 n을 참조합니다!
return x * n
# 내부 '함수 자체'를 반환합니다. (괄호를 치지 않음)
return multiplier
# 1. n=3으로 세팅된 곱하기 기계를 만듭니다.
times3 = make_multiplier(3)
# 원래대로라면 make_multiplier가 끝났으니 n=3도 사라져야 하지만...
# 2. 내부 함수가 실행될 때 여전히 n=3을 기억하고 있습니다!
print(times3(10)) # 30
print(times3(5)) # 15
1.2 자유 변수 (Free Variable)를 품은 클로저
함수가 끝나면 그 안의 변수들은 보통 메모리에서 우주 먼지처럼 사라집니다. 하지만 위의 예제처럼, 내부 함수가 외부 함수의 변수(n)를 물고 밖으로 튀어나오면, 파이썬은 그 변수를 지우지 않고 내부 함수만의 ‘비밀 보물상자’에 영원히 가둬둡니다.
이렇게 “자신이 만들어진 환경(변수)을 닫아서(Close) 기억하고 있는 함수” 현상을 클로저(Closure)라고 부릅니다. 이때 기억된 외부 변수를 자유 변수라고 합니다.
내부 함수의 __closure__ 속성을 뜯어보면 실제로 값이 저장되어 있는 것을 확인할 수 있습니다.
# times3 함수 안에 저장된 클로저(비밀 상자) 열어보기
# cell_contents 안에 숫자 3이 살아있는 것을 확인할 수 있습니다!
print(times3.__closure__[0].cell_contents) # 3
이 클로저의 강력한 기억력을 바탕으로, 데코레이터는 기존 함수의 상태나 매개변수를 잃어버리지 않고 기억하며 마법을 부릴 수 있게 됩니다.
서브목차