이펙티브 파이썬 Item 21. 변수 영역과 클로저의 상호작용 방식을 이해하라
- 프로그래밍 언어/파이썬
- 2023. 10. 19.
요약
- 클로저는 자유변수를 참조하는 함수다.
- 파이썬의 변수 참조는 다음 순서로 이루어진다
- 함수가 선언된 내부 영역
- 함수를 둘러싼 영역
- 모듈
- 빌트인 영역(len, str 등이 선언된)
- 변수 참조 순서를 고려해서 필요한 경우 nonlocal 키워드를 이용해 자유변수임을 알려줘야한다. 그렇지 않으면 기대하지 않은 방식으로 동작한다.
- nonlocal 키워드는 가급적이면 적게 써야한다. nonlocal 키워드 선언 부분과 변수가 실제로 사용되는 부분이 멀어지면 이해하기 어려운 코드가 되기 때문이다.
이펙티브 파이썬 Item 21. 변수 영역과 클로저의 상호작용 방식을 이해하라
# helper는 클로저가 됨.
def sort_priority(values, group):
def helper(x):
if x in group:
return 0,x
return 1,x
values.sort(key=helper)
n = [8,3,1,2,5,4,7,6]
group = {2,3,5,7}
sort_priority(n, group)
print(n)
>>>
[2, 3, 5, 7, 1, 4, 6, 8]
다음 코드에서 helper 함수는 정상적으로 사용된다. 이것은 helper()가 클로저로 동작했기 때문이다.
- 클로저 : 자신이 정의된 영역 밖의 변수(자유변수)를 참조하는 함수다. 파이썬에서 클로저를 지원하기 때문에 helper()는 group을 참조할 수 있게 된다.
- 파이썬에서 함수는 일급 객체다. 변수로 전달, If 문에서 함수 객체끼리 비교하는 곳에서 사용할 수 있다.
def sort_priority(values, group):
found = False
def helper(x):
if x in group:
# helper 안의 found는 자유변수가 아님. 즉, 외부의 found랑 무관함.
found = True
return 0,x
return 1,x
values.sort(key=helper)
return found
n = [8,3,1,2,5,4,7,6]
group = {2,3,5,7}
print(sort_priority(n, group))
>>>
False
클로저를 이용할 때, 변수의 범위에 주의를 기울이지 않으면 실수하기 쉽다.
- 만약 주어진 group 안에 원하는 수가 있다면 found = True로 설정한 후 반환해주는 함수를 만들었다고 가정해보자.
- 이 때, 결과는 True일 것을 기대하지만 실제로는 False가 나온다. (기대하지 않은 결과가 나옴)
왜 이렇게 동작하는 것일까? 파이썬에서 변수를 참조하는 순서를 고려해보면 알 수 있다.
- 함수가 선언된 영역에서 변수를 찾음.
- 현재 함수를 둘러싼 영역에서 변수를 찾음.
- 현재 코드가 들어있는 모듈에서 변수를 찾음.
- 내장 영역(built-in scope) (len, str 등의 함수가 들어있는 영역)
found는 helper() 내부에 선언되어 있기 때문에 1번에 대응되는 케이스가 된다. 즉, sort_priority()에 선언된 found와 helper()에 선언된 found는 서로 다른 변수다. 이런 이유 때문에 기대하지 않은 결과가 나타난다.
# nonlocal은 가급적이면 사용하지 마라.
# nonlocal로 선언된 부분 ↔ 실제 변수가 사용되는 시점이 멀어지면, 이해하기 어려워진다.
def sort_priority(values, group):
found = False
def helper(x):
nonlocal found # found는 지역변수가 아니라 자유변수임을 알려줌.
if x in group:
found = True
return 0,x
return 1,x
values.sort(key=helper)
return found
n = [8,3,1,2,5,4,7,6]
group = {2,3,5,7}
print(sort_priority(n, group))
이 부분을 해결하기 위해서 found가 지역변수가 아니라는 것을 알려주기만 하면 된다.
- nonlocal 키워드를 이용해 처리할 수 있다. nonlocal 키워드는 모듈 수준 이상으로 변수가 찾아올라가도록 하지는 않는다.
- nonlocal 키워드가 이 부분을 해결해주지만, 가급적이면 사용하지 않아야한다. nonlocal이 선언된 부분과 실제 변수가 사용되는 영역이 멀어지게 되면 이해하기 어려운 코드가 되기 때문이다.
'프로그래밍 언어 > 파이썬' 카테고리의 다른 글
이펙티브 파이썬 Item 26. functools.wrap을 사용해 함수 데코레이터를 정의하라 (0) | 2023.10.19 |
---|---|
이펙티브 파이썬 Item 25. 위치로만 인자를 지정하게 하거나 키워드로만 인자를 지정하게 해서 함수 호출을 명확하게 만들라 (1) | 2023.10.19 |
이펙티브 파이썬 Item 65. try/except/else/finally의 각 블록을 잘 활용하라 (0) | 2023.10.18 |
이펙티브 파이썬 Item 20. None을 반환하기보다는 예외를 발생시켜라 (0) | 2023.10.18 |
Effective Python Item 22. 변수 위치 인자를 사용해 시각적인 잡음을 줄여라 (0) | 2023.10.15 |