Документация Python неофициальный перевод
Содержание страницы

tokenize – Токенизатор исходного кода Pythontokenize – Tokenizer for Python source

Исходный код: Lib/tokenize.py


Модуль tokenize предоставляет лексический анализатор для исходного кода Python, реализованный на Python. Анализатор в этом модуле также возвращает комментарии в виде токенов, что делает его полезным для реализации «pretty-printers», включая цветовые выделители для отображения на экране.

Чтобы упростить обработку потока токенов, все токены операторов и разделителей, а также Ellipsis возвращаются с использованием общего типа токена OP. Точный tип можно определить, проверив свойство exact_type у именованного кортежа, возвращаемого функцией tokenize.tokenize().

Токенизация входных данныхTokenizing Input

Основной точкой входа является генератор:

tokenize.tokenize(readline)

Генератор tokenize() требует один аргумент, readline, который должен быть вызываемым объектом, предоставляющим тот же интерфейс, что и метод io.IOBase.readline() файловых объектов. Каждый вызов функции должен возвращать одну строку входных данных в виде байтов.

Генератор создаёт 5-кортежи со следующими элементами: тип токена; строка токена; 2-кортеж (srow, scol) из целых чисел, указывающих строку и столбец, где токен начинается в исходном коде; 2-кортеж (erow, ecol) из целых чисел, указывающих строку и столбец, где токен заканчивается; и строка, в которой был найден токен. Передаваемая строка (последний элемент кортежа) является физической строкой. 5-кортеж возвращается в виде именованного кортежа с именами полей: type string start end line.

Возвращаемый именованный кортеж имеет дополнительное свойство с именем exact_type, которое содержит точный тип оператора для токенов OP. Для всех остальных типов токенов exact_type равно полю type именованного кортежа.

Изменено в версии 3.1: Добавлена поддержка именованных кортежей.

Изменено в версии 3.3: Добавлена поддержка exact_type.

tokenize() определяет исходную кодировку файла, проверяя наличие UTF-8 BOM или кодировочной метки, в соответствии с PEP 263.

tokenize.generate_tokens(readline)

Токенизирует исходный код, читая строки Unicode вместо байтов.

Как и tokenize(), аргумент readline является вызываемым объектом, возвращающим одну строку входных данных. Однако generate_tokens() ожидает, что readline будет возвращать объект str, а не bytes.

Результатом является итератор, возвращающий именованные кортежи, точно как tokenize(). Он не возвращает токен ENCODING.

Все константы из модуля token также экспортируются из tokenize.

Предоставляется ещё одна функция для обращения процесса токенизации. Это полезно для создания инструментов, которые токенизируют скрипт, изменяют поток токенов и записывают изменённый скрипт обратно.

tokenize.untokenize(iterable)

Преобразует токены обратно в исходный код Python. Итерируемый объект должен возвращать последовательности как минимум из двух элементов: типа токена и строки токена. Все дополнительные элементы последовательности игнорируются.

Восстановленный скрипт возвращается в виде одной строки. Результат гарантированно токенизируется обратно в соответствии с входными данными, что обеспечивает преобразование без потерь и полную обратимость. Гарантия распространяется только на тип токена и строку токена, поскольку расстояния между токенами (позиции столбцов) могут измениться.

Он возвращает байты, закодированные с использованием токена ENCODING, который является первым токеном последовательности, выводимой tokenize(). Если во входных данных нет токена кодировки, вместо этого возвращается str.

tokenize() необходимо определить кодировку исходных файлов, которые он токенизирует. Функция, которую он использует для этого, доступна:

tokenize.detect_encoding(readline)

Функция detect_encoding() используется для определения кодировки, которая должна использоваться для декодирования файла исходного кода Python. Она требует один аргумент, readline, так же, как генератор tokenize().

Она вызовет readline максимум дважды и вернёт используемую кодировку (в виде строки) и список любых строк (не декодированных из байтов), которые она прочитала .

Он определяет кодировку по наличию UTF-8 BOM или кодировочной метки, как указано в PEP 263. Если присутствуют и BOM, и метка, но они не согласуются, будет возбуждено SyntaxError. Обратите внимание: если найден BOM, в качестве кодировки будет возвращена 'utf-8-sig'.

Если кодировка не указана, то будет возвращено значение по умолчанию 'utf-8'.

Используйте open() для открытия файлов исходного кода Python: он использует detect_encoding() для определения кодировки файла.

tokenize.open(filename)

Открывает файл в режиме только для чтения, используя кодировку, определённую с помощью detect_encoding().

Новое в версии 3.2.

exception tokenize.TokenError

Возникает, когда докстринг или выражение, которое может быть разбито на несколько строк, не завершено нигде в файле, например:

"""Beginning of
docstring

или:

[1,
 2,
 3

Обратите внимание, что незакрытые строки в одинарных кавычках не вызывают возникновения ошибки. Они токенизируются как ERRORTOKEN, после чего следует токенизация их содержимого.

Использование командной строкиCommand-Line Usage

Новое в версии 3.3.

Модуль tokenize может быть выполнен как скрипт из командной строки. Это просто:

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

Принимаются следующие опции:

-h, --help

показывает это справочное сообщение и завершает работу

-e, --exact

отображает имена токенов с использованием точного типа

Если указан filename.py, его содержимое токенизируется в stdout. В противном случае токенизация выполняется из stdin.

ПримерыExamples

Пример переписчика скриптов, преобразующего литералы чисел с плавающей запятой в объекты 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" (Windows) и "e-07" (не Windows). Поскольку
    мы показываем только 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:

$ python -m tokenize -e 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:          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      ''

Пример программной токенизации файла: чтение строк Unicode вместо байтов с помощью 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)