클로저
1. 클로저
클로저는 파이썬에만 있는 개념이 아니라 다른 프로그래밍 언어에서도 중요한 프로그래밍 개념으로, 함수 내 함수가 외부 변수를 참조하여 보존하는 것을 얘기합니다.
# 1번: 클로저가 아닌경우
def outer_function():
def inner_function():
return 100 + 100
return inner_function
# 2번: 클로저인 경우
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
inner = outer_function(100)
inner(200) # inner 입장에서 100을 변경할 수 있는 방법이 없습니다.
위 1번 예제에서는 inner_function이 외부 변수를 참조하고 있진 않습니다. 함수를 반환하니 고차함수이지만, 클로저는 아닙니다.
2번 예제에서 outer_function은 inner_function을 반환합니다. inner_function은 외부 함수의 변수 x를 참조하고 있습니다. 따라서 outer_function(100)을 호출하면 x = 100이라는 상태를 기억하는 클로저가 만들어집니다.
여기서 눈여겨볼 점은 outer_function의 실행이 이미 끝났는데도 지역 변수 x가 사라지지 않는다는 것입니다. 그래서 inner(200)을 호출하면 기억해둔 100을 꺼내와 300을 돌려줍니다. 클로저가 inner_function의 코드뿐만 아니라 x = 100이라는 상태까지 함께 '기억'하고 있기 때문입니다.
실제로 어떤 값을 기억하고 있는지 들여다볼 수도 있습니다.
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
inner = outer_function(100)
print(inner(200)) # 300
print(inner.__closure__[0].cell_contents) # 100, 기억하고 있는 값
2. 클로저의 활용
클로저는 외부에서 직접 접근할 수 없는 변수를 '감추는' 방법을 제공합니다. 이를 통해 데이터 은닉과 캡슐화를 구현할 수 있습니다. 아래 코드에서 count 변수는 밖에서 직접 건드릴 수 없고, 오직 counter()를 호출하는 방법으로만 값을 늘릴 수 있습니다.
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
counter_a = make_counter()
print(counter_a()) # 1
print(counter_a()) # 2
위 코드에 등장한 nonlocal은 바깥 함수의 변수를 수정하겠다고 선언하는 키워드입니다. 바로 다음 장에서 자세히 다룹니다.
또한 클로저는 함수를 반환하기 때문에 함수형 프로그래밍과 데코레이터의 구현에 필수적입니다. 데코레이터는 nonlocal에 이어 설명하도록 하겠습니다.