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(). Если в входе нет токена кодировки, он возвращает строку вместо этого.
tokenize() необходимо определять кодировку файлов источников, которые он токенизирует. Функция, которую он использует для этого, доступна:
-
tokenize.detect_encoding(readline) -
Функция
detect_encoding()используется для определения кодировки, которая должна быть использована для декодирования файла исходного кода Python. Она требует один аргумент, readline, точно так же, как и генераторtokenize().Она может вызвать readline максимум дважды и вернуть используемую кодировку (как строку) и список любых строк (не декодированных из байтов), которые она прочитала.
Она определяет кодировку по наличию UTF-8 BOM или кодировочного куки, как указано в 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, за которым следует токенизация их содержимого.
Использование в командной строке
Введено в версии 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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/library/tokenize.html