Spec-Zone.ru › Python 3.12

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-элементные кортежи со следующими элементами: тип токена; строка токена; 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() определяет кодировку исходного файла, проверяя наличие BOM UTF-8 или объявления кодировки согласно 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 или объявления кодировки, как указано в PEP 263. Если присутствуют и BOM, и объявление кодировки, но они не совпадают, будет вызвано исключение 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.

Примеры

Пример переписывателя скриптов, преобразующего литералы с плавающей точкой в объекты 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/tokenize.html

Spec-Zone.ru

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