Spec-Zone.ru › Python 3.9

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

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

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

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

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

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

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 или кодировочное cookie в соответствии с PEP 263.

tokenize.generate_tokens(readline)

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

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

Результат — итератор, возвращающий кортежи с именованными полями, точно так же, как 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 или кодировочного cookie, как указано в PEP 263. Если присутствуют и BOM, и cookie, но они не совпадают, будет поднято исключение 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, после чего содержимое токенизируется.

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

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

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

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

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

-h, --help

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

-e, --exact

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

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

Примеры

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

Spec-Zone.ru

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