# `tokenize` — 파이썬 소스를 위한 토크나이저

소스 코드: Lib/tokenize.py

`tokenize` 모듈은 파이썬으로 구현된 파이썬 소스 코드를 위한 어휘 스캐너를 제공합니다. 이 모듈의 스캐너는 주석도 토큰으로 반환하므로, 화면 디스플레이용 색상 표시기를 포함하여 “예쁜 인쇄기”를 구현하는 데 유용합니다.

토큰 스트림 처리를 단순화하기 위해, 모든 연산자와 구분자 토큰과 `Ellipsis`는 범용 `OP` 토큰 유형을 사용하여 반환됩니다. 정확한 유형은 `tokenize.tokenize()`에서 반환된 네임드 튜플의 `exact_type` 프로퍼티를 확인하여 파악할 수 있습니다.

경고

Note that the functions in this module are only designed to parse syntactically valid Python code (code that does not raise when parsed using `ast.parse()`). The behavior of the functions in this module is undefined when providing invalid Python code and it can change at any point.

## 입력 토큰화하기

기본 진입점은 제너레이터입니다:

tokenize.tokenize(readline)

  `tokenize()` 제너레이터는 하나의 인자 readline을 요구합니다. 이 인자는 파일 객체의 `io.IOBase.readline()` 메서드와 같은 인터페이스를 제공하는 콜러블 객체여야 합니다. 함수를 호출할 때마다 한 줄의 입력을 바이트열로 반환해야 합니다.

  제너레이터는 다음 멤버를 갖는 5-튜플을 생성합니다: 토큰 유형; 토큰 문자열; 토큰이 소스에서 시작하는 줄과 열을 지정하는 정수의 2-튜플 `(srow, scol)`; 토큰이 소스에서 끝나는 줄과 열을 지정하는 정수의 2-튜플 `(erow, ecol)`과 토큰이 발견된 줄. 전달된 줄(마지막 튜플 항목)은 물리적 줄입니다. 5-튜플은 필드 이름이 `type string start end line` 인 네임드 튜플로 반환됩니다.

  반환된 네임드 튜플에는 `OP` 토큰에 대한 정확한 연산자 유형이 포함된 `exact_type`이라는 추가 프로퍼티가 있습니다. 다른 모든 토큰 유형에서 `exact_type`은 네임드 튜플 `type` 필드와 같습니다.

  버전 3.1에서 변경: 네임드 튜플에 대한 지원이 추가되었습니다.

  버전 3.3에서 변경: `exact_type`에 대한 지원이 추가되었습니다.

  `tokenize()`는 PEP 263에 따라 UTF-8 BOM이나 인코딩 쿠키를 찾아 파일의 소스 인코딩을 결정합니다.

tokenize.generate_tokens(readline)

  바이트열 대신에 유니코드 문자열을 읽는 소스를 토큰화합니다.

  `tokenize()`와 마찬가지로, readline 인자는 한 줄의 입력을 반환하는 콜러블입니다. 그러나, `generate_tokens()`는 readline이 바이트열이 아닌 문자열 객체를 반환할 것으로 기대합니다.

  결과는 정확히 `tokenize()`처럼 네임드 튜플을 산출하는 이터레이터입니다. `ENCODING` 토큰을 산출하지 않습니다.

`token` 모듈의 모든 상수도 `tokenize`에서 내보냅니다.

토큰화 프로세스를 역전시키는 또 다른 함수가 제공됩니다. 이것은 스크립트를 토큰화하고, 토큰 스트림을 수정한 후, 수정된 스크립트를 다시 쓰는 도구를 만드는 데 유용합니다.

tokenize.untokenize(iterable)

  토큰을 파이썬 소스 코드로 역 변환합니다. iterable은 최소한 토큰 유형과 토큰 문자열의 두 요소가 있는 시퀀스를 반환해야 합니다. 추가 시퀀스 요소는 무시됩니다.

  결과는 다시 토큰화하면 입력과 일치함이 보장되어, 변환은 무손실이고 왕복이 보장됩니다. 보증은 토큰 유형과 토큰 문자열에만 적용되어, 토큰 간의 간격(열 위치)은 변경될 수 있습니다.

  `tokenize()` 에 의해 출력되는 첫 번째 토큰 시퀀스인 `ENCODING` 토큰을 사용하여 인코딩된 바이트열을 반환합니다. 입력에 인코딩 토큰이 없으면, 대신 str을 반환합니다.

`tokenize()`는 토큰화하는 소스 파일의 인코딩을 감지해야 합니다. 이 작업을 수행하는 데 사용되는 함수를 사용할 수 있습니다:

tokenize.detect_encoding(readline)

  `detect_encoding()` 함수는 파이썬 소스 파일을 디코딩할 때 사용해야 하는 인코딩을 감지하는 데 사용됩니다. `tokenize()` 제너레이터와 같은 방식으로, 하나의 인자 readline을 요구합니다.

  readline을 최대 두 번 호출하고, 사용된 인코딩(문자열로)과 읽은 줄들(바이트열에서 디코드 되지 않습니다)의 리스트를 반환합니다.

  PEP 263에 지정된 대로 UTF-8 BOM이나 인코딩 쿠키의 존재로부터 인코딩을 검색합니다. BOM과 쿠키가 모두 있지만 서로 일치하지 않으면 `SyntaxError`가 발생합니다. BOM이 발견되면, `'utf-8-sig'`가 인코딩으로 반환됩니다.

  인코딩이 지정되지 않으면, 기본값인 `'utf-8'`이 반환됩니다.

  `open()`을 사용하여 파이썬 소스 파일을 여십시오: `detect_encoding()`을 사용하여 파일 인코딩을 감지합니다.

tokenize.open(filename)

  `detect_encoding()`에 의해 감지된 인코딩을 사용하여 읽기 전용 모드로 파일을 엽니다.

  Added in version 3.2.

exception tokenize.TokenError

  여러 줄로 나눌 수 있는 독스트링이나 표현식이 파일의 어디에서도 완료되지 않을 때 발생합니다, 예를 들어:

      """Beginning of
      docstring

  또는:

      [1,
       2,
       3

## 명령 줄 사용법

Added in version 3.3.

`tokenize` 모듈은 명령 줄에서 스크립트로 실행될 수 있습니다. 이렇게 간단합니다:

    python -m tokenize [-e] [filename.py]

허용되는 옵션은 다음과 같습니다:

-h, --help

  이 도움말 메시지를 표시하고 종료합니다

-e, --exact

  정확한 유형(exact_type)을 사용하여 토큰 이름을 표시합니다

`filename.py`가 지정되면 그 내용은 표준출력(stdout)으로 토큰화됩니다. 그렇지 않으면, 표준입력(stdin)에 대해 토큰화가 수행됩니다.

## 예제

float 리터럴을 Decimal 객체로 변환하는 스크립트 재 작성기의 예제:

    from tokenize import tokenize, untokenize, NUMBER, STRING, NAME, OP
    from io import BytesIO

    def decistmt(s):
        """문장 문자열에 있는 float를 Decimal로 치환합니다.

        >>> from decimal import Decimal
        >>> s = 'print(+21.3e-5*-.1234/81.7)'
        >>> decistmt(s)
        "print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"

        지수 형식은 플랫폼 C 라이브러리에서 상속됩니다. 알려진 경우는 "e-007" (윈도우) 와 "e-07"
        (윈도우 외) 입니다. 우리는 단지 12자리 숫자를 보여주고 있고, 13번째 숫자는 5에 가깝지
        않으므로, 출력의 나머지 부분은 플랫폼 독립적이어야 합니다.

        >>> exec(s)  #doctest: +ELLIPSIS
        -3.21716034272e-0...7

        Decimal을 사용한 계산의 결과는 모든 플랫폼에서 같아야 합니다.

        >>> exec(decistmt(s))
        -3.217160342717258261933904529E-7
        """
        result = []
        g = tokenize(BytesIO(s.encode('utf-8')).readline)  # 문자열을 토큰화합니다
        for toknum, tokval, _, _, _ in g:
            if toknum == NUMBER and '.' in tokval:  # NUMBER 토큰을 바꿔치기합니다
                result.extend([
                    (NAME, 'Decimal'),
                    (OP, '('),
                    (STRING, repr(tokval)),
                    (OP, ')')
                ])
            else:
                result.append((toknum, tokval))
        return untokenize(result).decode('utf-8')

명령 줄에서 토큰화하는 예제. 스크립트:

    def say_hello():
        print("Hello, World!")

    say_hello()

는 다음 출력으로 토큰화됩니다. 여기서 첫 번째 열은 토큰이 발견된 줄/열 좌표의 범위이고, 두 번째 열은 토큰의 이름이며, 마지막 열은 토큰의 값입니다 (있다면)

    $ python -m tokenize hello.py
    0,0-0,0:            ENCODING       'utf-8'
    1,0-1,3:            NAME           'def'
    1,4-1,13:           NAME           'say_hello'
    1,13-1,14:          OP             '('
    1,14-1,15:          OP             ')'
    1,15-1,16:          OP             ':'
    1,16-1,17:          NEWLINE        '\n'
    2,0-2,4:            INDENT         '    '
    2,4-2,9:            NAME           'print'
    2,9-2,10:           OP             '('
    2,10-2,25:          STRING         '"Hello, World!"'
    2,25-2,26:          OP             ')'
    2,26-2,27:          NEWLINE        '\n'
    3,0-3,1:            NL             '\n'
    4,0-4,0:            DEDENT         ''
    4,0-4,9:            NAME           'say_hello'
    4,9-4,10:           OP             '('
    4,10-4,11:          OP             ')'
    4,11-4,12:          NEWLINE        '\n'
    5,0-5,0:            ENDMARKER      ''

정확한 토큰 유형 이름은 `-e` 옵션을 사용하여 표시할 수 있습니다:

    0,0-0,0:            ENCODING       'utf-8'
    1,0-1,3:            NAME           'def'
    1,4-1,13:           NAME           'say_hello'
    1,13-1,14:          LPAR           '('
    1,14-1,15:          RPAR           ')'
    1,15-1,16:          COLON          ':'
    1,16-1,17:          NEWLINE        '\n'
    2,0-2,4:            INDENT         '    '
    2,4-2,9:            NAME           'print'
    2,9-2,10:           LPAR           '('
    2,10-2,25:          STRING         '"Hello, World!"'
    2,25-2,26:          RPAR           ')'
    2,26-2,27:          NEWLINE        '\n'
    3,0-3,1:            NL             '\n'
    4,0-4,0:            DEDENT         ''
    4,0-4,9:            NAME           'say_hello'
    4,9-4,10:           LPAR           '('
    4,10-4,11:          RPAR           ')'
    4,11-4,12:          NEWLINE        '\n'
    5,0-5,0:            ENDMARKER      ''

`generate_tokens()`로 바이트열 대신 유니코드 문자열을 읽는, 프로그래밍 방식으로 파일을 토큰화하는 예:

    import tokenize

    with tokenize.open('hello.py') as f:
        tokens = tokenize.generate_tokens(f.readline)
        for token in tokens:
            print(token)

또는 `tokenize()`로 직접 바이트열을 읽는 예:

    import tokenize

    with open('hello.py', 'rb') as f:
        tokens = tokenize.tokenize(f.readline)
        for token in tokens:
            print(token)