Spec-Zone.ru › Python 3.14

tokenize — Токенизатор исходного кода Python

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

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

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

Предупреждение

Обратите внимание, что функции этого модуля предназначены только для разбора синтаксически корректного кода Python (кода, при разборе которого с помощью ast.parse() не возникает исключений). Поведение функций этого модуля при передаче некорректного кода Python не определено и может измениться в любой момент.

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

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

tokenize.tokenize(readline)

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

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

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

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

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

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

tokenize.generate_tokens(readline)

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

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

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

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

Также предоставляется функция для обратного преобразования токенов. Она полезна для создания инструментов, которые токенизируют скрипт, изменяют поток токенов и записывают изменённый скрипт обратно.

tokenize.untokenize(iterable)

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

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

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

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

tokenize.detect_encoding(readline)

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

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

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

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

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

tokenize.open(filename)

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

Добавлено в версии 3.2.

exception tokenize.TokenError

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

"""Beginning of
docstring

или:

[1,
 2,
 3

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

Добавлено в версии 3.3.

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

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

Доступны следующие параметры:

-h, --help

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

-e, --exact

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

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

Примеры

Пример скрипта для переписывания кода, который преобразует литералы типа float в объекты Decimal:

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

def decistmt(s):
    """Substitute Decimals for floats in a string of statements.

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

    The format of the exponent is inherited from the platform C library.
    Known cases are "e-007" (Windows) and "e-07" (not Windows).  Since
    we're only showing 12 digits, and the 13th isn't close to 5, the
    rest of the output should be platform-independent.

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

    Output from calculations with Decimal should be identical across all
    platforms.

    >>> exec(decistmt(s))
    -3.217160342717258261933904529E-7
    """
    result = []
    g = tokenize(BytesIO(s.encode('utf-8')).readline)  # tokenize the string
    for toknum, tokval, _, _, _ in g:
        if toknum == NUMBER and '.' in tokval:  # replace NUMBER tokens
            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)

© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/tokenize.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API