Home

(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기

Published in python
October 01, 2025
2 min read
(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기

안녕하세요, 코딩하는곰입니다! 🐾 파이썬을 사용하면서 함수 안에 함수를 정의해 본 경험이 있으신가요? 그렇다면 ‘클로저(Closure)‘라는 개념을 한 번쯤은 들어보셨을 겁니다. 클로저는 파이썬의 강력하면서도 다소 이해하기 어려운 개념 중 하나인데요, 특히 nonlocal 키워드와 함께 사용될 때 그 진가를 발휘합니다. 오늘은 파이썬의 클로저와 nonlocal 키워드에 대해 깊이 있게 파헤쳐보겠습니다. 단순한 개념 설명을 넘어, 실제 프로젝트에서 어떻게 활용하는지, 어떤 함정에 빠질 수 있는지까지 상세하게 알아보도록 하겠습니다. 이 글을 읽고 나면 여러분도 클로저를 자유자재로 다룰 수 있는 고급 파이썬 개발자가 될 수 있을 거예요!

클로저(Closure)의 기본 개념 이해하기

클로저는 간단히 말해 자신을 둘러싼 스코프(네임스페이스)의 상태를 기억하는 함수입니다. 다른 함수 안에서 정의된 내부 함수가, 외부 함수의 변수를 참조하면서 외부 함수의 실행이 끝난 후에도 그 상태를 유지할 수 있을 때 클로저가 생성됩니다.

클로저의 기본 구조

def outer_function(x): # 외부 함수
def inner_function(y): # 내부 함수
return x + y # 외부 함수의 변수 x를 참조
return inner_function # 내부 함수를 반환
closure = outer_function(10)
result = closure(5)
print(result) # 15

위 예제에서 inner_functionouter_function의 매개변수 x를 참조하고 있습니다. outer_function의 실행이 끝난 후에도 closurex=10이라는 상태를 기억하고 있어 closure(5)를 호출하면 15를 반환합니다.

클로저의 3가지 조건

  1. 중첩 함수(Nested Function): 함수 내부에 또 다른 함수가 정의되어야 합니다.
  2. 자유 변수(Free Variable) 참조: 내부 함수가 외부 함수의 변수를 참조해야 합니다.
  3. 함수 반환: 외부 함수가 내부 함수를 반환해야 합니다.

왜 클로저를 사용할까?

클로저는 다음과 같은 상황에서 매우 유용합니다:

  • 상태 유지: 함수가 호출 사이에 상태를 유지해야 할 때
  • 정보 은닉: 전역 변수를 사용하지 않고 데이터를 캡슐화할 때
  • 데코레이터 구현: 함수의 동작을 수정하거나 확장할 때
  • 콜백 함수: 이벤트 핸들러나 콜백에서 특정 상태를 유지할 때

클로저의 실제 활용 예제: 카운터 구현

def create_counter():
count = 0
def counter():
nonlocal count # 외부 함수의 변수를 수정하기 위해 nonlocal 사용
count += 1
return count
return counter
# 카운터 생성
my_counter = create_counter()
print(my_counter()) # 1
print(my_counter()) # 2
print(my_counter()) # 3
# 새로운 카운터 생성 (독립적인 상태 유지)
another_counter = create_counter()
print(another_counter()) # 1

이 예제에서 각 카운터는 자신만의 count 상태를 독립적으로 유지합니다. 이것이 바로 클로저의 힘이라고 할 수 있습니다.

(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기
(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기


🛠️ 프로그래밍 팁과 트릭을 찾고 있다면, (자바 역사) 가전제품을 위한 언어에서 세계 최고의 프로그래밍 언어로 - Green 프로젝트의 시작를 참고해보세요.

nonlocal 키워드의 필요성과 사용법

클로저를 이해했다면 이제 nonlocal 키워드가 왜 필요한지 알아볼 차례입니다. nonlocal은 파이썬 3에서 도입된 키워드로, 중첩 함수에서 외부 함수의 변수를 수정할 수 있게 해줍니다.

nonlocal이 없을 때 발생하는 문제

def broken_counter():
count = 0
def counter():
count += 1 # UnboundLocalError 발생!
return count
return counter
# 이 코드는 실행 시 에러가 발생합니다
try:
counter = broken_counter()
counter()
except UnboundLocalError as e:
print(f"에러 발생: {e}")

위 코드는 UnboundLocalError: local variable 'count' referenced before assignment 에러를 발생시킵니다. 파이썬은 count += 1에서 count를 지역 변수로 간주하기 때문입니다.

nonlocal로 문제 해결하기

def working_counter():
count = 0
def counter():
nonlocal count # count가 외부 함수의 변수임을 명시
count += 1
return count
return counter
# 정상적으로 동작합니다
counter = working_counter()
print(counter()) # 1
print(counter()) # 2

nonlocal vs global

nonlocalglobal은 비슷해 보이지만 중요한 차이가 있습니다:

  • global: 모듈 수준의 전역 변수를 참조
  • nonlocal: 가장 가까운 enclosing 스코프의 변수를 참조
global_var = "전역"
def outer():
outer_var = "외부"
def inner():
global global_var
nonlocal outer_var
global_var = "수정된 전역"
outer_var = "수정된 외부"
print(f"inner 내부: {global_var}, {outer_var}")
inner()
print(f"outer 내부: {global_var}, {outer_var}")
outer()
print(f"전역: {global_var}")

여러 단계의 중첩에서 nonlocal 사용하기

def level1():
x = "level1"
def level2():
x = "level2" # 이 x는 level1의 x와 다른 변수
def level3():
nonlocal x # level2의 x를 참조
x = "level3에서 수정"
level3()
print(f"level2에서: {x}") # level3에서 수정
level2()
print(f"level1에서: {x}") # 변경되지 않음
level1()

nonlocal의 주의사항

  1. 변수가 존재해야 함: nonlocal로 선언한 변수는 외부 스코프에 이미 존재해야 합니다.
  2. 전역 변수 참조 불가: nonlocal로 전역 변수를 참조할 수 없습니다.
  3. 여러 변수 동시 선언: nonlocal x, y, z 형태로 여러 변수를 한 번에 선언할 수 있습니다.
def multiple_variables():
a = 1
b = 2
c = 3
def inner():
nonlocal a, b, c # 여러 변수 동시 선언
a += 10
b += 20
c += 30
return a + b + c
result = inner()
print(f"a={a}, b={b}, c={c}, result={result}")
multiple_variables() # a=11, b=22, c=33, result=66

(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기
(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기


정확한 시간 기록이 필요한 실험이나 트레이닝에는 실시간 스톱워치 기능을 활용하는 것이 좋습니다.

실전 프로젝트에서의 클로저와 nonlocal 활용

이제 이론을 넘어 실제 프로젝트에서 클로저와 nonlocal을 어떻게 활용하는지 알아보겠습니다.

1. 데코레이터(Decorator) 구현

데코레이터는 클로저의 가장 대표적인 활용 예입니다.

import time
from functools import wraps
def timer_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} 실행 시간: {end_time - start_time:.4f}초")
return result
return wrapper
@timer_decorator
def expensive_operation(n):
"""시간이 오래 걸리는 연산을 시뮬레이션"""
sum = 0
for i in range(n):
sum += i
return sum
# 사용 예제
result = expensive_operation(1000000)
print(f"결과: {result}")

2. 상태를 유지하는 함수 생성기

def create_multiplier(factor):
"""주어진 factor로 숫자를 곱하는 함수 생성"""
def multiplier(x):
return x * factor
return multiplier
# 다양한 배수 함수 생성
double = create_multiplier(2)
triple = create_multiplier(3)
quadruple = create_multiplier(4)
print(double(5)) # 10
print(triple(5)) # 15
print(quadruple(5)) # 20

3. 캐시 구현 (Memoization)

def create_cached_function(func):
"""함수의 결과를 캐싱하는 데코레이터"""
cache = {}
def cached_func(*args):
if args in cache:
print(f"캐시에서 결과 반환: {args}")
return cache[args]
result = func(*args)
cache[args] = result
print(f"새로운 계산: {args} -> {result}")
return result
return cached_func
@create_cached_function
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 피보나치 수열 계산 (캐시 덕분에 효율적)
print(fibonacci(10))

4. 객체 지향 스타일의 상태 관리 대체

클로저를 사용하면 간단한 경우에 클래스 대신 사용할 수 있습니다.

def create_person(name, age):
"""클로저를 사용한 객체 지향 스타일의 상태 관리"""
def get_name():
return name
def get_age():
return age
def set_age(new_age):
nonlocal age
age = new_age
def introduce():
return f"안녕하세요, 저는 {name}이고 {age}살입니다."
# 메서드들을 딕셔너리로 반환
return {
'get_name': get_name,
'get_age': get_age,
'set_age': set_age,
'introduce': introduce
}
# 사용 예제
person = create_person("코딩하는곰", 20)
print(person['introduce']()) # 안녕하세요, 저는 코딩하는곰이고 20살입니다.
person['set_age'](21)
print(person['introduce']()) # 안녕하세요, 저는 코딩하는곰이고 21살입니다.

5. 콜백 함수에 상태 추가하기

def create_event_handler(button_name, click_count=0):
"""버튼 클릭 핸들러 생성"""
def handle_click():
nonlocal click_count
click_count += 1
print(f"{button_name} 버튼이 {click_count}번 클릭되었습니다.")
return click_count
return handle_click
# 다양한 버튼 핸들러 생성
save_handler = create_event_handler("저장")
delete_handler = create_event_handler("삭제")
# 버튼 클릭 시뮬레이션
save_handler() # 저장 버튼이 1번 클릭되었습니다.
save_handler() # 저장 버튼이 2번 클릭되었습니다.
delete_handler() # 삭제 버튼이 1번 클릭되었습니다.
save_handler() # 저장 버튼이 3번 클릭되었습니다.

6. 실전 팁과 최적화 기법

# 1. 클로저의 __closure__ 속성 확인하기
def outer(x):
def inner():
return x
return inner
closure_func = outer(10)
print(f"클로저 속성: {closure_func.__closure__}")
print(f"자유 변수 값: {closure_func.__closure__[0].cell_contents}")
# 2. 성능 고려사항
def performance_test():
"""클로저의 성능 특성 이해"""
import timeit
# 클로저를 사용한 경우
def create_with_closure():
data = list(range(1000))
def process():
return sum(data)
return process
# 클로저를 사용하지 않은 경우
def create_without_closure():
def process(data):
return sum(data)
return process
# 성능 비교
closure_time = timeit.timeit(
"func()",
setup="from __main__ import create_with_closure; func = create_with_closure()",
number=10000
)
no_closure_time = timeit.timeit(
"func(data)",
setup="from __main__ import create_without_closure; func = create_without_closure(); data = list(range(1000))",
number=10000
)
print(f"클로저 사용: {closure_time:.4f}초")
print(f"클로저 미사용: {no_closure_time:.4f}초")
performance_test()

(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기
(파이썬 클로저 완벽 가이드) nonlocal 키워드로 중첩 함수의 변수 스코프 마스터하기


계산할 때 이전 기록이 필요하다면, 계산 이력 기능이 있는 웹 계산기를 활용해보세요.

마치며

클로저와 nonlocal 키워드는 파이썬의 함수형 프로그래밍 기능을 완성하는 중요한 요소입니다. 처음에는 다소 추상적으로 느껴질 수 있지만, 실제로 활용해보면 그 유용성을 깨닫게 될 거예요. 오늘 우리가 함께 배운 내용을 정리해보면:

  • 클로저는 자신의 스코프 외부에 있는 변수를 기억하는 함수입니다
  • nonlocal 은 중첩 함수에서 외부 함수의 변수를 수정할 때 필요합니다
  • 이러한 개념들은 데코레이터, 상태 유지, 콜백 관리 등 다양한 상황에서 활용됩니다 처음에는 단순한 카운터나 메시지 생성기부터 시작해서, 점점 더 복잡한 데코레이터나 상태 관리 시스템으로 나아가보세요. 연습이 가장 좋은 선생님입니다! 여러분도 이제 클로저와 nonlocal의 매력에 푹 빠져서, 더 우아하고 효율적인 파이썬 코드를 작성하실 수 있을 거라 믿습니다. 다음번에도 또 다른 유용한 파이썬 팁으로 찾아뵙겠습니다. 코딩하는곰이었습니다! 함께 성장하는 파이썬 여정, 즐거우셨나요? 🐻💻 궁금한 점이 있으시다면 언제든지 댓글로 질문해주세요! 여러분의 소중한 의견을 기다리겠습니다.

남들과 겹치지 않는 닉네임이 필요할 때는 연관성 높은 키워드 기반 닉네임 생성기를 사용해보세요.









최상의 건강을 위한 영양가득한 식품과 정보! life-plus.co.kr 바로가기
최상의 건강을 위한 영양가득한 식품과 정보! life-plus.co.kr 바로가기



다채로운 문화축제와 공연 소식을 공유하는 블로그! culturestage.co.kr 바로가기
다채로운 문화축제와 공연 소식을 공유하는 블로그! culturestage.co.kr 바로가기



비트코인 세계로의 첫걸음! 지금 가입하고 거래 수수료 할인 혜택 받으세요! bitget.com 바로가기
비트코인 세계로의 첫걸음! 지금 가입하고 거래 수수료 할인 혜택 받으세요! bitget.com 바로가기




Tags

#developer#coding#python

Share

Previous Article
React useEffect 무한 루프 완벽 해결 가이드 의존성 배열의 모든 것

Table Of Contents

1
클로저(Closure)의 기본 개념 이해하기
2
nonlocal 키워드의 필요성과 사용법
3
실전 프로젝트에서의 클로저와 nonlocal 활용
4
마치며

Related Posts

(파이썬 기초 마스터) 함수 정의(def)와 호출, return의 모든 것 - 코딩하는곰의 친절한 가이드
December 26, 2025
3 min