The Annotated Python Language Reference #3

2. 구문 분석

2.1. 줄 구조(Line structure)

2.1.7. 빈 줄

스페이스, 탭, 폼 피드(formfeed) 와 주석만으로 구성된 논리적인 줄은 무시된다. (즉 NEWLINE 토큰이 만들어지지 않는다.) 대화형으로 문장이 입력되는 도중에는 빈 줄의 처리가 REPL 구현에 따라 달라질 수 있다. 표준 대화형 인터프리터에서는, 완전히 빈 줄(즉 공백이나 주석조차 없는 것)은 다중 행 문장을 종료시킨다.

APLR

스페이스(space)는 ' ' 문자를 가리킬 때 사용합니다. 반면 공백(whitespace)은 스페이스, 탭, 폼피드 문자들을 통칭할 때 사용합니다.

APLR

REPL 은 Read-Eval-Print Loop 의 약자입니다. 문장을 입력받고 실행한 후 결과를 출력하는 것을 반복하는 대화형 환경의 인터페이스를 뜻합니다.

2.1.8. 들여쓰기

논리적인 줄의 제일 앞에 오는 공백(스페이스와 탭)은 줄의 들여쓰기 수준을 계산하는 데 사용되고, 이는 다시 문장들의 묶음을 결정하는 데 사용되게 된다.

탭은 (왼쪽에서 오른쪽으로) 1~8개의 스페이스로 변환되는데, 치환된 후의 총 스페이스 문자 수가 8의 배수가 되도록 맞춘다. (유닉스에서 사용되는 규칙에 맞추려는 것이다.) 첫 번째 비 공백 문자 앞에 나오는 공백의 총수가 줄의 들여쓰기를 결정한다. 들여쓰기는 역 슬래시를 사용해서 여러 개의 물리적인 줄로 나눠질 수 없다; 첫 번째 역 슬래시 이전의 공백이 들여쓰기를 결정한다.

APLR

역 슬래시 앞에 공백 문자 이외의 문자가 오는 경우, 명시적 줄 연결이 들여쓰기 수준을 바꾸지 못함은 자명합니다. 하지만 역 슬래시 이전에 공백과 탭문자들만 있는 경우, 그 다음 줄의 처음에 등장하는 공백이나 탭이 더해져서 들여쓰기 수준이 결정되는지 여부는 좀 애매할 수 있습니다. 이 문단은 그 경우를 명확히하고 있는데, 오직 첫번째 물리적 줄에서 들여쓰기 수준이 결정된다는 것입니다. 아주 예외적인 경우에 대한 정의인데, 아예 이런 상황을 만들지 않는 것이 바람직합니다.

소스 파일이 탭과 스페이스를 섞어 쓰는 경우, 탭이 몇 개의 스페이스에 해당하는지에 따라 다르게 해석될 수 있으면 TabError 를 일으킨다.

APLR

파이썬의 구문 분석기가 탭을 최대 8개의 공백으로 변환한다는 규칙은 늘 유지됩니다. 하지만 편집기는 설정 상태에 따라 다른 값을 사용하고 있을 수 있습니다. 만약 이 설정 상태에 따라 코드가 다르게 해석될 수 있다면 문제점을 발견하기가 무척 어렵게 됩니다. 때문에 이런 가능성이 있는 경우 TabError 를 일으킵니다. 탭과 공백을 섞어 쓰더라도, 다르게 해석될 여지가 없는 경우는 예외를 발생시키지 않습니다. 다르게 해석된다는 것은 문장들의 묶음이 다르게 결정된다는 것을 뜻합니다.

APLR

TabErrorSyntaxError 의 서브 클래스입니다. 이처럼 구문분석 단계에서 발생하는 오류는 SyntaxError 로 이어집니다.

크로스-플랫폼 호환성 유의 사항: UNIX 이외의 플랫폼에서 편집기들이 동작하는 방식 때문에, 하나의 파일 내에서 들여쓰기를 위해 탭과 스페이스를 섞어 쓰는 것은 현명한 선택이 아니다. 다른 플랫폼들에서는 최대 들여쓰기 수준에 제한이 있을 수도 있다는 점도 주의해야 한다.

폼 피드 문자는 줄의 처음에 나올 수 있다; 앞서 설명한 들여쓰기 수준 계산에서는 무시된다. 페이지 넘김 문자 앞에 공백이나 탭이 있는 경우는 정의되지 않은 효과를 줄 수 있다 (가령, 스페이스 수가 0으로 초기화될 수 있다).

연속된 줄의 들여쓰기 수준은, 스택을 사용해서, 다음과 같은 방법으로 INDENT와 DEDENT 토큰을 만드는 데 사용된다.

파일의 첫 줄을 읽기 전에 0하나를 스택에 넣는다(push); 이 값은 다시 꺼내는(pop) 일이 없다. 스택에 넣는 값은 항상 스택의 아래에서 위로 올라갈 때 단조 증가한다. 각 논리적인 줄의 처음에서 줄의 들여쓰기 수준이 스택의 가장 위에 있는 값과 비교된다. 같다면 아무런 일도 일어나지 않는다. 더 크다면 그 값을 스택에 넣고 하나의 INDENT 토큰을 만든다. 더 작다면 이 값은 스택에 있는 값 중 하나여만 한다. 이 값보다 큰 모든 스택의 값들을 꺼내고(pop), 꺼낸 횟수만큼의 DEDENT 토큰을 만든다. 파일의 끝에서, 스택에 남아있는 0보다 큰 값의 개수만큼 DEDENT 토큰을 만든다.

여기에 (혼란스럽다 할지라도) 올바르게 들여쓰기 된 파이썬 코드 조각이 있다:

def perm(l):
        # l 의 모든 가능한 순열(permutation)의 리스트를 계산한다
    if len(l) <= 1:
                  return [l]
    r = []
    for i in range(len(l)):
             s = l[:i] + l[i+1:]
             p = perm(s)
             for x in p:
              r.append(l[i:i+1] + x)
    return r

다음 예는 여러 가지 들여쓰기 에러를 보여준다:

 def perm(l):                       # 에러: 첫줄을 들여쓰기 했다
for i in range(len(l)):             # 에러: 들여쓰기 하지 않았다
    s = l[:i] + l[i+1:]
        p = perm(l[:i] + l[i+1:])   # 에러: 들여쓰기가 올 수 없다
        for x in p:
                r.append(l[i:i+1] + x)
            return r                # 에러: 일관성없는 내어쓰기

(사실, 처음 세 개의 에러는 파서가 감지한다. 단지 마지막 에러만 구문 분석기가 감지한다. --- return r 의 들여쓰기가 스택에 있는 값과 일치하지 않는다.)

2.1.9. 토큰 사이의 공백

논리적인 줄의 처음과 문자열 리터럴을 제외하고, 공백 문자인 스페이스, 탭, 폼 피드는 토큰을 분리하기 위해 섞어 쓸 수 있다. 두 토큰을 붙여 쓸 때 다른 토큰으로 해석될 수 있는 경우만 토큰 사이에 공백이 필요하다. (예를 들어, ab 는 하나의 토큰이지만, a b 는 두 개의 토큰이다.)

APLR

반대로 토큰 사이에 공백이 꼭 필요하지 않은 경우에, 공백을 넣는 것은 공백을 넣지 않은 것과 동일한 결과를 줍니다. 가령 -5-5 두개의 토큰으로 구성됩니다. 이를 - 5 로 써도 같은 결과를 줍니다. 또한 ' hello '.strip() 처럼 리터럴의 메서드를 호출하는 것은 자연스러운 표현입니다. 하지만 숫자 리터럴의 경우는 . 이 소수점으로 해석되기 때문에 사용하기가 곤란합니다. 이런 경우 . 앞에 공백을 삽입하면 됩니다. 7 .bit_length().

2.2. 다른 토큰들

NEWLINE, INDENT, DEDENT 와는 별도로, 다음과 같은 유형의 토큰들이 존재한다: 식별자(identifier), 키워드(keyword), 리터럴(literal), 연산자(operator), 구분자(delimiter). (앞에서 살펴본 줄 종료 이외의) 공백 문자들은 토큰이 아니지만, 토큰을 분리하는 역할을 담당한다. 모호할 경우, 왼쪽에서 오른쪽으로 읽을 때, 하나의 토큰은 올바르고 가능한 한 최대 길이의 문자열로 구성되는 것을 선호한다.