1. 클로저가 뭐지?
클로저는 “함수가 만들어질 때의 외부 변수(자유 변수) 를 기억했다가, 나중에 함수를 호출할 때도 그 값을 계속 사용할 수 있는” 함수예요. 클래스를 쓰지 않아도 상태를 은근슬쩍 유지할 수 있다는 게 장점입니다
예제: 평균 누적 함수 만들기
# Closure 사용
def closure_ex1():
# 자유변수 / 클로저 영역
series = []
def averager(v):
series.append(v)
print('inner >> {} / {}'.format(series, len(series)))
return sum(series) / len(series)
return averager
avg_closure1 = closure_ex1()
# 누적
print(avg_closure1(10)) # 10.0
print(avg_closure1(20)) # 15.0
print(avg_closure1(30)) # 20.0
어떻게 동작하나?
- closure_ex1()가 실행될 때 series = []가 만들어집니다.
- 내부 함수 averager는 바깥 스코프의 series를 캡처합니다.
- closure_ex1()은 averager를 반환하고 끝나지만, averager는 series를 기억하고 있어요.
- 그래서 avg_closure1(…)를 여러 번 호출해도 series에 값이 계속 누적됩니다.
2. 클로저 내부 들여다보기(inspection)
파이썬은 함수 객체가 내부 정보를 꽤 많이 노출합니다. 아래 코드는 그중 클로저 관련 속성 위주로 확인한 예예요.
# function inspection
print(dir(avg_closure1)) # 함수 객체가 가진 속성들
print()
print(dir(avg_closure1.__code__)) # 코드 객체가 가진 속성들
print()
print(avg_closure1.__code__.co_freevars) # ('series',) - 캡처된 자유 변수 이름
print()
print(dir(avg_closure1.__closure__[0])) # 클로저 셀(cell) 객체 속성
print()
print(avg_closure1.__closure__[0].cell_contents) # 실제로 캡처된 값: series 리스트 내용
print()
설명
- __code__.co_freevars
→ 자유 변수 이름들의 튜플. 위 예제에선 ('series',)가 나옵니다. - __closure__
→ 셀(cell) 객체들의 튜플. 각 셀에 자유 변수의 실제 값이 담겨 있어요.- avg_closure1.__closure__[0].cell_contents
→ series의 현재 리스트 내용이 그대로 보입니다(예: [10, 20, 30]).
- avg_closure1.__closure__[0].cell_contents
이 함수가 어떤 외부 변수를 캡처했는지(co_freevars), 그 실제 값이 무엇인지(closure … cell_contents) 를 직접 확인할 수 있다!
3. 언제 클로저를 쓰면 좋을까?
- 상태를 가진 작은 함수가 필요할 때(카운터, 평균, 최근값 유지 등)
- 클래스 만들기엔 과하지만 간단한 상태 유지가 필요할 때
- 콜백/고차함수에서 컨텍스트 일부를 묶어두고 싶을 때
4. 클래스의 __call__과 비교
- 클로저: 함수가 외부 변수를 캡처해서 상태를 “기억”
- __call__ 객체: 클래스 인스턴스가 속성으로 상태를 저장하면서 함수처럼 호출 가능
(둘 다 “상태 + 호출” 패턴이지만, 저장 위치가 다름: 자유 변수 vs 인스턴스 속성)
정리하면
이 예제처럼 클로저를 쓰면 간단한 상태 유지형 함수를 쉽게 만들 수 있고,
co_freevars, __closure__를 이용하면 어떤 변수를 캡처했고 값이 어떻게 변했는지까지 투명하게 확인할 수 있습니다.
'파이썬 > 기초 프로그래밍' 카테고리의 다른 글
| 파이썬 클로저와 nonlocal — 언제 필요할까? (0) | 2025.09.08 |
|---|---|
| 파이썬 클로저(Closure)와 nonlocal 키워드 (0) | 2025.09.08 |
| __call__ 재정의: 클래스도 함수처럼 사용하기 (1) | 2025.09.07 |
| functools.partial 사용법: 인수 고정 → 콜백 함수로 활용하기 (0) | 2025.09.07 |
| 일급 객체(First-class Object)란 무엇일까? (0) | 2025.09.07 |