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, а не bytes.Результат — итератор, возвращающий именованные кортежи, точно так же, как
tokenize(). Он не возвращает токенENCODING.
Все константы из модуля token также экспортируются из tokenize.
Предоставляется другая функция для обратного преобразования токенизации. Это полезно для создания инструментов, которые токенизируют скрипт, изменяют поток токенов и записывают обратно изменённый скрипт.
-
tokenize.untokenize(iterable) -
Преобразует токены обратно в исходный код Python. Итератор iterable должен возвращать последовательности, содержащие по крайней мере два элемента: тип токена и строку токена. Любые дополнительные элементы последовательности игнорируются.
Восстановленный скрипт возвращается как одна строка. Результат гарантированно токенизируется обратно в соответствие с вводом, так что преобразование является безошибочным и гарантируются циклы «туда и обратно». Гарантия относится только к типу токена и строке токена, так как интервалы между токенами (позиции столбцов) могут измениться.
Возвращает байты, закодированные с использованием токена
ENCODING, который является первой последовательностью токенов, выводимойtokenize(). Если токена кодировки нет во входных данных, возвращается строка вместо этого.
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'.Используйте
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.8/library/tokenize.html