Closure는 자신을 둘러싼 바깥쪽 함수가 종료된 후에도 그 안의 변수를 기억하고 사용할 수 있는 함수를 말합니다. 함수가 정의될 시점의 바깥 상태를 통째로 감싸서(enclose) 보관하는 것입니다.
Closure의 조건
바깥쪽 함수가 존재하는 함수라는 점에서 closure는 중첩함수(Nested Function)여야 한다는 것을 알 수 있습니다. 하지만 모든 중첩함수가 closure인 것은 아닙니다. Clousure는 아래 세 가지 조건을 만족해야 합니다.
- 중첩함수일 것
- 안쪽 함수가 바깐쪽 함수의 변수를 참조할 것
- 바깥쪽 함수가 안쪽 함수를 반환값으로 사용할 것
# 조건 1 : 중접함
def outer_func(message):
# 조건들을 만족한 inner_func는 closure가 됩니다.
def inner_func():
print(message) # 조건 2. 바깥쪽 변수를 참조
return inner_func # 조건 3. 안쪽 변수를 반환
# outer_func는 실행을 마쳤기 때문에 "Hello" 인자는 메모리에서 사라져야 하지만...
my_func = outer_func("Hello")
# 실행해보면 "Hello"를 기억하고 출력합니다.
my_func()
여기서 inner_func는 closure가 됩니다. outer_func가 종료되어 스택 프레임에서 사라지더라도, 반환된 inner_func는 자신이 참조했던 message 변수를 힙(Heap) 메모리에 따로 저장하게 됩니다.
Closure의 사용처
Clousre는 이미 사라져버려 접근이 불가능한 함수의 변수값을 자신만 가지고 있습니다. 이 때문에 클래스를 만들기에는 너무 거창하고, 전역 변수를 쓰기에는 보안이나 오염이 걱정될 때 private 타입의 변수처럼 사용할 수 있습니다.
또한 함수가 호출될 때마다 특정 상태를 기억하도록 만들수도 있습니다. 상태값을 갱신하도록 만든다면 바깥쪽 함수를 읽는 것만이 아니라 쓰는 것도 해야 하는데, 이 때 nonlocal* 예약어를 사용해야 합니다.
*nonlocal : global 예약어와 비슷하게 바깥 범위의 변수를 지역 함수에서 사용할 수 있도록 해줍니다. 단, 그 범위가 전역이 아닌 바깥쪽 함수까지로 제한됩니다.
def make_counter():
count = 0
def counter(): # counter는 closure
nonlocal count # 바깥쪽 변수를 수정하기 위해 필요
count += 1
return count
return counter
c1 = make_counter()
print(c1()) # 1
print(c1()) # 2 (상태가 유지됨)
만약 위 코드에서 count를 nonlocal 없이 그냥 쓴다면, counter에서 초기값이 없어 오류가 발생할 것입니다.
'Language > Python' 카테고리의 다른 글
| [Python] Event Loop (0) | 2026.02.16 |
|---|---|
| [Python] Library | 08. asyncio (0) | 2026.02.15 |
| [Python] Garbage Collection (0) | 2026.02.15 |
| [Python] 동시성과 GIL(Global Interpreter Lock) (0) | 2026.02.15 |
| [Python] Syntax | 02. List (0) | 2026.02.15 |