클로저(closures)는 파이썬의 강력한 메커니즘으로, 주변 컨텍스트에서 "기억된" 데이터를 가진 함수를 생성할 수 있게 해줍니다.
함수형 언어와 파이썬에서 함수는 일급 객체입니다. 함수는 자신을 둘러싼(외부) 범위의 변수를 '클로저'하는 새 함수 반환할 수 있습니다.
개발자들은 종종 클로저 내부의 클로저된 변수가 어떻게 "존재하는지", 읽히거나 쓰일 때 어떻게 작동하는지, 그리고 이를 안전하게 (특히 가변 객체와 함께) 어떻게 다루는지 혼동합니다.
내부 함수가 외부 함수의 변수를 사용하는 경우, 이 변수들은 자동으로 "기억됩니다" — 외부 함수가 이미 종료되었더라도 말이죠. 변수를 읽는 것은 명백하지만, 값을 변경해야 하는 경우에는 nonlocal 키워드를 사용해야 합니다. 가변 객체(list, dict)와 함께 작업할 때는 특히 위험한 지역입니다.
예시:
def outer(): count = 0 def inner(): nonlocal count count += 1 return count return inner counter = outer() print(counter()) # 1 print(counter()) # 2
주요 특징:
nonlocal을 사용하세요 (그렇지 않으면 지역 변수를 생성하게 됩니다).nonlocal 없이 클로저된 변수의 값을 변경할 수 있나요?
아니요. 새로운 값을 할당하려고 시도하면, nonlocal을 지정하지 않으면 파이썬은 이를 새 지역 변수로 인식하고, 오래된 값은 외부로 나가지 않습니다.
예시:
def make_counter(): count = 0 def inner(): count += 1 # UnboundLocalError 오류! return count return inner
클로저를 통해 외부 범위에 인수를 전달할 수 있나요?
예, 클로저는 외부 범위에서 접근할 수 있는 모든 변수를 "기억합니다", 클래스 속성, 전역 변수 등을 포함합니다. 하지만 이러한 변수를 변경하려면 특별한 노력이 필요합니다 (예: nonlocal 또는 global 사용).
클로저 내부의 가변 객체는 어떻게 되나요?
가변 객체에 대한 참조가 클로저에 클로저될 경우, 예를 들어 리스트의 경우, nonlocal 없이 그 내용을 수정할 수 있지만, 변수를 재할당하려고 하면 nonlocal이 필요합니다.
예시:
def make_appender(): result = [] def append(x): result.append(x) # 가능합니다! return result return append f = make_appender() print(f(1)) # [1] print(f(2)) # [1, 2]
개발자가 클로저를 작성하고 nonlocal 없이 변수를 변경하여 UnboundLocalError가 발생합니다.
장점:
단점:
상태 관리를 위한 클로저에서 nonlocal을 명시적으로 사용하는 경우.
장점:
단점: