LEGB 룰 — Python 이 이름 찾는 곳
x 같은 이름 참조하면 Python 은 (순서대로) Local scope, Enclosing 함수 scope, Global (모듈) scope, 마지막으로 Built-ins (print, len 등) 을 찾아. 처음 찾는 곳이 이김. 그래서 함수 안에 정의된 이름이 같은 이름의 모듈 레벨 이름을 가려 — Python 이 local 을 먼저 찾아.
Closure — 출생지를 기억하는 함수
inner 함수가 enclosing 함수의 이름을 참조할 수 있어. 그 inner 함수를 반환하면 — 그 바인딩들을 들고 가. 그게 closure. inner 함수가 enclosing 함수의 변수에 대한 참조를 들고, enclosing 함수가 끝난 후에도. decorator 가 작동하는 방식, factory 함수가 작동하는 방식, 콜백이 컨텍스트 기억하는 방식 — 다 이거.
읽기 vs 쓰기 — 비대칭
inner 함수는 enclosing 변수를 *읽는* 건 자유. *쓰기* 는 nonlocal 필요. 모듈 레벨 변수 *쓰기* 는 global 필요. 이 선언 없이 할당하면 — 같은 이름의 새 local 바인딩 만들어서 바깥 이름 가려. closure 안에서 카운터 변경하려는 거의 모든 초보가 여기서 걸려.
fns = [lambda: i for i in range(5)]. 모든 lambda 가 같은 i 를 참조, 끝나면 4. *현재 값* 캡쳐하려면 lambda i=i: i (디폴트 인자가 정의 시점에 캡쳐). 모두가 한 번씩 물려.
closure vs class — 언제 어느 쪽
state 들고 있는 함수가 필요하면 closure 가 가볍고 idiomatic. state 공유하는 메서드 여러 개 필요하면 class 가 더 명확. 그 사이의 흐릿한 영역은 Python 디자인의 영원한 질문 — 모든 경우에 맞는 룰 같은 건 없어.