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

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

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


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

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

32.7.1. Токенизация ввода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, которое содержит точный тип оператора для токенов token.OP. Для всех остальных типов токенов exact_type равно полю type именованного кортежа.

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

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

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

Все константы из модуля token также экспортируются из tokenize, а также три дополнительных значения типа токена:

tokenize.COMMENT

Значение токена, используемое для обозначения комментария.

tokenize.NL

Значение токена, используемое для обозначения незавершающего перевода строки. Токен NEWLINE обозначает конец логической строки кода Python; токены NL создаются, когда логическая строка кода продолжается на нескольких физических строках.

tokenize.ENCODING

Значение токена, указывающее кодировку, используемую для декодирования байтов исходного кода в текст. Первый токен, возвращаемый tokenize(), всегда будет токеном ENCODING.

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

tokenize.untokenize(iterable)

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

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

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

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

tokenize.detect_encoding(readline)

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

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

Он определяет кодировку по наличию BOM UTF-8 или маркера кодировки, как указано в 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, а затем токенизируется их содержимое.

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

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

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

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

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

-h, --help

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

-e, --exact

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

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

32.7.3. Примеры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      ''