---
title: "클로저는 끝난 함수의 변수를 어떻게 기억할까"
author: "Lee"
published_at: "2026-10-30T13:07:04.869Z"
updated_at: "2026-09-30T10:11:11.526Z"
tags: ["컴퓨터공학","프로그래밍언어"]
canonical_url: "https://ariser.io/@writer_a1cd615ab19e/%ED%81%B4%EB%A1%9C%EC%A0%80%EB%8A%94-%EB%81%9D%EB%82%9C-%ED%95%A8%EC%88%98%EC%9D%98-%EB%B3%80%EC%88%98%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EA%B8%B0%EC%96%B5%ED%95%A0%EA%B9%8C"
ai_assisted: false
---

# 클로저는 끝난 함수의 변수를 어떻게 기억할까

[원문](https://ariser.io/@writer_a1cd615ab19e/%ED%81%B4%EB%A1%9C%EC%A0%80%EB%8A%94-%EB%81%9D%EB%82%9C-%ED%95%A8%EC%88%98%EC%9D%98-%EB%B3%80%EC%88%98%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EA%B8%B0%EC%96%B5%ED%95%A0%EA%B9%8C)

함수가 다른 함수를 만들어 반환할 때, 안쪽 함수가 바깥쪽의 변수를 나중에도 사용할 수 있다. 클로저는 함수의 코드와 그 함수가 정의된 환경에 대한 연결을 함께 다루는 개념이다. 함수가 자신의 인자나 지역 변수 밖에 있는 이름을 참조할 때, 그 이름을 어떤 바인딩으로 해석할지 보존한다. 바깥 함수의 실행이 끝났다는 사실만으로 필요한 환경이 사라지는 것은 아니다.

![반환된 두 카운터 함수가 서로 다른 환경에 저장된 n 값을 유지하는 클로저 구조](/api/v1/media/19feb976-45bc-49c4-b68b-ef3c5bcb099f)

*클로저는 함수가 정의된 환경과 연결되며, 캡처한 바인딩은 상태를 공유하거나 따로 유지할 수 있다.*

## 호출한 곳보다 정의된 곳이 중요하다

어휘적 범위에서는 이름의 의미가 소스 코드에서 함수가 정의된 위치와 중첩 관계에 따라 정해진다. 같은 이름의 변수가 호출한 쪽에 있어도 그것으로 자동 교체되지 않는다. [Python 실행 모델](https://docs.python.org/3/reference/executionmodel.html)은 가까운 바깥 범위를 따라 이름을 찾는 규칙과 `nonlocal`이 바깥 함수의 바인딩을 가리키는 방식을 설명한다. 클로저를 이해하려면 함수의 실행 순서와 이름의 범위를 구분해야 한다.

예를 들어 `make_counter`가 지역 변수 `n = 0`을 만들고 내부 함수 `next_value`를 반환한다고 하자. 내부 함수는 Python에서 `nonlocal n`을 선언한 뒤 `n += 1`을 수행하고 결과를 반환할 수 있다. 바깥 호출이 끝난 뒤에도 반환된 함수를 두 번 호출하면 1, 2가 된다. 필요한 바인딩이 함수와 연결돼 유지되기 때문이다.

## 기억하는 것은 언제나 값의 사진이 아니다

클로저가 변수를 잡았다고 생성 순간의 값을 무조건 복사해 고정하는 것은 아니다. 언어와 캡처 방식에 따라 바인딩이나 객체를 공유할 수 있다. Python에서 같은 바깥 호출로 만든 여러 내부 함수가 `n`을 참조하면 같은 상태를 볼 수 있다. 한 함수가 바꾸면 다른 함수에서 읽는 값도 달라진다. 반면 `make_counter`를 새로 호출해 만든 카운터는 보통 별도의 환경을 갖는다.

반복문에서 만든 함수들이 모두 마지막 반복값을 사용해 당황하는 사례도 이 차이에서 나온다. 함수가 실행될 때 같은 변수의 현재 바인딩을 읽도록 구성됐다면, 함수마다 생성 당시 값을 따로 보관하지 않는다. Python에서는 기본 인자를 이용해 그 시점의 값을 별도 인자로 저장하거나 함수 생성용 호출을 나눌 수 있다. 어떤 방식을 쓰든 실제 참조와 수명을 이해하는 것이 우선이다.

## 객체 없이도 작은 상태를 묶는다

클로저는 설정을 담은 콜백, 특정 접두사를 붙이는 문자열 함수, 간단한 카운터나 접근 권한이 제한된 상태를 만들 때 유용하다. 내부 환경을 외부에서 직접 다루지 않도록 하고 필요한 동작만 함수로 노출할 수 있다. 하지만 단순한 상수 인자를 미리 붙이는 부분 적용과 클로저가 완전히 같은 개념은 아니다. 부분 적용은 호출 인자를 줄이는 변환이고 클로저는 코드와 환경의 관계를 설명한다.

환경의 수명이 길어지는 데 따른 비용도 있다. 작은 콜백이 큰 객체를 참조하면 그 객체가 더 오래 살아남을 수 있다. 사용자 인터페이스의 이벤트 구독이나 장기 보관하는 함수 목록에서 이런 연결을 점검해야 한다. 구현은 필요한 값을 힙에 두거나 다른 표현을 사용할 수 있으므로, 바깥 함수의 전체 스택을 언제나 통째로 저장한다고 설명하는 것은 부정확하다.

캡처한 상태가 가변이라면 동시성 문제도 그대로 생긴다. 여러 실행 흐름이 하나의 카운터 클로저를 공유할 때 증가 연산이 자동으로 안전해지는 것은 아니다. 클로저는 상태를 어디에 숨길지와 얼마나 오래 유지할지 정리하는 도구다. 참조 방식, 공유 여부, 갱신 규칙을 함께 살피면 단순한 문법 편의를 넘어 함수가 상태를 가지고 살아가는 방식을 이해할 수 있다.

### 참고 자료

- [Python Language Reference — Execution model](https://docs.python.org/3/reference/executionmodel.html)
