파이썬은 모든 것을 다양한 범위의 사전에 보관한다는 점에서 조금 이상합니다. 원래의 a, b, c는 최상위 범위에 있으므로 최상위 사전에 있습니다. 함수에는 자체 사전이 있습니다. 당신이 도달 할 때 print(a)
와print(b)
문에 사전에 해당 이름의 이름이 없으므로 Python은 목록을 찾아 전역 사전에서 찾습니다.
이제 우리 c+=1
는 물론에 해당합니다 c=c+1
. 파이썬이 그 라인을 스캔 할 때, "aha, c라는 변수가 있는데, 이것을 내 로컬 스코프 사전에 넣겠습니다"라고 말합니다. 그런 다음 할당의 오른쪽에서 c에 대한 c에 대한 값을 찾으면 아직 값이없는 c라는 로컬 변수를 찾아서 오류를 발생시킵니다.
global c
위에서 언급 한 내용 은 파서에게 c
전역 범위 의 from을 사용 하므로 새로운 구문이 필요하지 않다는 것을 파서에게 알려줍니다 .
그것이 라인에 문제가 있다고 말하는 이유는 코드를 생성하기 전에 효과적으로 이름을 찾고 있기 때문에 어떤 의미에서는 아직 그 라인을 실제로하고 있다고 생각하지 않기 때문입니다. 나는 이것이 유용성 버그라고 주장하지만 일반적으로 컴파일러의 메시지를 너무 심각하게 받아들이지 않는 법을 배우는 것이 좋습니다 .
그것이 위안이라면, Guido가 모든 것을 설명하는 사전에 대해 쓴 것을 발견하기 전에이 같은 문제를 파고 실험하는 데 하루를 보냈습니다.
업데이트, 의견 참조 :
코드를 두 번 스캔하지는 않지만 lexing과 parsing의 두 단계로 코드를 스캔합니다.
이 코드 줄의 구문 분석이 어떻게 작동하는지 고려하십시오. 어휘 분석기는 소스 텍스트를 읽고 문법의 "가장 작은 구성 요소"인 렉 세스로 나눕니다. 그래서 라인에 도달하면
c+=1
그것은 그것을 다음과 같이 나눕니다.
SYMBOL(c) OPERATOR(+=) DIGIT(1)
파서는 결국 이것을 구문 분석 트리로 만들고 실행하려고하지만 할당이기 때문에 로컬 사전에서 c라는 이름을 찾고 그것을 보지 않고 사전에 삽입하여 표시합니다. 초기화되지 않은 것으로. 완전히 컴파일 된 언어에서는 기호 테이블로 이동하여 구문 분석을 기다릴 수 있지만 두 번째 패스의 사치가 없기 때문에 렉서 (Lexer)는 나중에 인생을 더 쉽게하기 위해 약간의 추가 작업을 수행합니다. 그런 다음 운영자 만 볼 수 있고 규칙에 "운영자 + =가있는 경우 왼쪽이 초기화되어야합니다"라고 말하고 "누가!"라고 말합니다.
여기서 요점은 아직 라인의 구문 분석을 시작하지 않았다는 것입니다. 입니다. 이것은 실제 구문 분석에 대한 모든 준비 과정이므로 행 카운터가 다음 행으로 진행되지 않았습니다. 따라서 오류를 알리더라도 여전히 이전 라인에서 오류를 생각합니다.
내가 말했듯이, 그것은 유용성 버그라고 주장 할 수 있지만 실제로는 매우 일반적인 것입니다. 일부 컴파일러는 그것에 대해 더 정직하고 "XXX 라인 또는 그 주변에 오류"라고 말하지만, 그렇지 않습니다.