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, а не bytes.

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

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

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

tokenize.untokenize(iterable)

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

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

Возвращает байты, закодированные с помощью токена 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'.

Используйте open() для открытия файлов исходного кода Python: он использует 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 указан, его содержимое токенизируется в стандартный вывод. В противном случае токенизация выполняется со стандартного ввода.

Примеры

Пример скрипта-переписателя, который преобразует литералы 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–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