tokenize
— Токенизатор для исходного кода Python
Модуль 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 или cookie кодировки в соответствии с PEP 263.
-
tokenize.
generate_tokens
(readline) Токенизация исходного кода из Юникод строки вместо байтов.
Как и
tokenize()
, аргумент readline является вызываемым, возвращающим одну строку ввода. Однакоgenerate_tokens()
ожидает, что readline вернёт строковый объект, а не байты.В результате итератор выдает именованные кортежи точно так же, как
tokenize()
. Он не отдаётENCODING
токен.
Все константы из модуля token
также экспортируются из tokenize
.
Предусмотрена ещё одна функция для обратного процесса токенизации. Это полезно для создания инструментов, которые токенизируют сценарий, изменяют поток маркеров и записывают изменённый скрипт.
-
tokenize.
untokenize
(iterable) Преобразует токены обратно в исходный код Python. iterable должен возвращать последовательности, содержащие как минимум два элемента: тип токена и строку токена. Любые дополнительные элементы последовательности игнорируются.
Восстановленный скрипт возвращается в виде одной строки. Результат гарантированно токенизируется обратно, чтобы соответствовать вводу, так что преобразование происходит без потерь и гарантируется двустороннее обращение. Гарантия распространяется только на тип токена и строку токена, т. к. расстояние между токенами (позиции столбцов) может измениться.
Возвращает байты, закодированные с использованием токена
ENCODING
, который является первой последовательностью токенов, выводимойtokenize()
. Если во входных данных нет токена кодировки, вместо этого возвращается str.
tokenize()
должна определять кодировку исходных файлов, которые она
токенизирует. Функция, которую она использует для этого, доступна:
-
tokenize.
detect_encoding
(readline) Функция
detect_encoding()
используется для определения кодировки, которую следует использовать для декодирования исходного файла Python. Она требует readline аргумента, так же, как генераторtokenize()
.Она вызовет readline не более двух раз и вернёт использованную кодировку (в виде строки) и список любых строк (не декодированных из байтов), которые она прочитал.
Она определяет кодировку по наличию спецификации UTF-8 или cookie файла кодировки, как указано в PEP 263. Если и спецификация, и cookie присутствуют, но не совпадают, будет вызвано
SyntaxError
. Обратите внимание, что если спецификация найдена, будет возвращена'utf-8-sig'
как кодировка.Если кодировка не указана, будет возвращено значение по умолчанию
'utf-8'
.Используйте
open()
для открытия исходных файлов Python: она используетdetect_encoding()
для определения кодировки файла.
-
tokenize.
open
(filename) Открывает файл в режиме только для чтения, используя кодировку, обнаруженную
detect_encoding()
.Добавлено в версии 3.2.
-
exception
tokenize.
TokenError
Вызывается, когда строка документа или выражение, которое может быть разделено на несколько строк, нигде в файле не завершены. Например
"""Начало строки документации
или же:
[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):
"""Заменяем Decimal на числа с плавающей запятой в строке операторов.
>>> from decimal import Decimal
>>> s = 'print(+21.3e-5*-.1234/81.7)'
>>> decistmt(s)
"print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"
Формат экспоненты унаследован от библиотеки платформы C. Известны
случаи «e-007» (Windows) и «e-07» (не Windows). Поскольку мы показываем
только 12 цифр, а 13-я не близка к 5, остальная часть вывода должна
быть независимой от платформы.
>>> exec(s) #doctest: +ELLIPSIS
-3.21716034272e-0...7
Результат вычислений с Decimal должен быть одинаковым на всех
платформах.
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
"""
result = []
g = tokenize(BytesIO(s.encode('utf-8')).readline) # токенизируем строку
for toknum, tokval, _, _, _ in g:
if toknum == NUMBER and '.' in tokval: # заменяем NUMBER токены
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 ''
Пример программной разметки файла, чтения строк Юникода вместо байтов с помощью
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)