파이썬의 nonlocal은 중첩 함수에서 바깥 함수의 지역 변수를 수정할 때 사용한다.
예를 들어 다음 코드는 에러가 발생한다.
def outer():
count = 0
def inner():
count += 1
inner()
inner() 안에서 count += 1처럼 값을 변경하면 파이썬은 count를 inner()의 지역 변수로 판단한다.
이때 nonlocal을 사용하면 된다.
def outer():
count = 0
def inner():
nonlocal count
count += 1
inner()
print(count)
outer()
출력:
1
즉,
nonlocal count
는
count는 현재 함수의 지역 변수가 아니라 바깥 함수의 변수다.
라는 의미다.
nonlocal이 필요 없을 수도 있다리스트의 경우에는 조금 다르다.
def outer():
arr = []
def inner():
arr.append(1)
inner()
print(arr)
이 코드는 nonlocal 없이도 정상 동작한다.
[1]
그 이유는 arr 변수 자체를 바꾼 것이 아니라, arr가 가리키는 리스트 객체의 내부를 수정했기 때문이다.
arr.append(1) # 리스트 내부 수정
arr[0] = 10 # 리스트 내부 수정
arr.clear() # 리스트 내부 수정
이런 경우에는 nonlocal이 필요 없다.
반면 리스트 자체를 새 리스트로 재할당하면 필요하다.
def outer():
arr = []
def inner():
nonlocal arr
arr = [1, 2, 3]
여기서는
arr = [1, 2, 3]
처럼 arr 변수 자체가 다른 객체를 가리키도록 바꾸기 때문이다.
핵심은 mutable인지 아닌지가 아니라 변수 자체를 재할당하는지다.
arr.append(1) # nonlocal 필요 없음
arr[0] = 10 # 필요 없음
arr = [1, 2, 3] # nonlocal 필요
딕셔너리와 set도 같은 원리다.
d["a"] = 1 # nonlocal 필요 없음
s.add(1) # nonlocal 필요 없음
한 줄로 정리하면:
중첩 함수에서 바깥 변수 자체를 재할당하려면
nonlocal, 객체 내부만 수정한다면 보통 필요 없다.
태그가 아쉬워요