Содержание страницы
32.7. tokenize – Токенизатор для исходного кода Python¶tokenize – Tokenizer for Python source
Исходный код: Lib/tokenize.py
Модуль tokenize предоставляет лексический сканер для исходного кода Python,
реализованный на Python. Сканер в этом модуле также возвращает комментарии как токены,
что делает его полезным для реализации «pretty-printers», включая
раскрашиватели для отображения на экране.
Чтобы упростить обработку потока токенов, все токены операторов и
разделителей, а также Ellipsis возвращаются с использованием
общего типа токена OP. Точный
tип можно определить, проверив свойство exact_type у
именованного кортежа, возвращаемого функцией tokenize.tokenize().
32.7.1. Токенизация входных данных¶Tokenizing Input
Основной точкой входа является генератор:
-
tokenize.tokenize(readline)¶ Генератор
tokenize()требует один аргумент, readline, который должен быть вызываемым объектом, предоставляющим тот же интерфейс, что и методio.IOBase.readline()файловых объектов. Каждый вызов функции должен возвращать одну строку входных данных в виде байтов.Генератор создаёт 5-кортежи со следующими элементами: тип токена; строка токена; 2-кортеж
(srow, scol)из целых чисел, задающих строку и столбец, где токен начинается в исходном коде; 2-кортеж(erow, ecol)из целых чисел, задающих строку и столбец, где токен заканчивается в исходном коде; и строка, в которой был найден токен. Передаваемая строка (последний элемент кортежа) – это логическая строка; строки продолжения включены. 5-кортеж возвращается как именованный кортеж с именами полей:type string start end line.Возвращаемый именованный кортеж имеет дополнительное свойство с именем
exact_type, которое содержит точный тип оператора для токеновtoken.OP. Для всех остальных типов токеновexact_typeравно полюtypeименованного кортежа.Изменено в версии 3.1: Добавлена поддержка именованных кортежей.
Изменено в версии 3.3: Добавлена поддержка
exact_type.tokenize()определяет исходную кодировку файла, проверяя наличие UTF-8 BOM или кодировочной метки, в соответствии с PEP 263.
Все константы из модуля token также экспортируются из
tokenize, а также три дополнительных значения типа токена:
-
tokenize.COMMENT¶ Значение токена, используемое для обозначения комментария.
-
tokenize.NL¶ Значение токена, используемое для обозначения незавершающего перевода строки. Токен NEWLINE обозначает конец логической строки кода Python; токены NL создаются, когда логическая строка кода продолжается на нескольких физических строках.
-
tokenize.ENCODING¶ Значение токена, указывающее кодировку, используемую для декодирования байтов исходного кода в текст. Первый токен, возвращаемый
tokenize(), всегда будет токеном ENCODING.
Предоставляется ещё одна функция для обращения процесса токенизации. Это полезно для создания инструментов, которые токенизируют скрипт, изменяют поток токенов и записывают изменённый скрипт обратно.
-
tokenize.untokenize(iterable)¶ Преобразует токены обратно в исходный код Python. Итерируемый объект должен возвращать последовательности как минимум из двух элементов: типа токена и строки токена. Все дополнительные элементы последовательности игнорируются.
Восстановленный скрипт возвращается в виде одной строки. Результат гарантированно токенизируется обратно в соответствии с входными данными, что обеспечивает преобразование без потерь и полную обратимость. Гарантия распространяется только на тип токена и строку токена, поскольку расстояния между токенами (позиции столбцов) могут измениться.
Он возвращает байты, закодированные с использованием токена ENCODING, который является первой последовательностью токенов, выдаваемой
tokenize().
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
Обратите внимание, что незакрытые строки в одинарных кавычках не вызывают
ошибки. Они токенизируются как ERRORTOKEN, а затем токенизируется их содержимое.
32.7.2. Использование в командной строке¶Command-Line Usage
Новое в версии 3.3.
Модуль tokenize может быть выполнен как скрипт из командной строки. Это просто:
python -m tokenize [-e] [filename.py]
Принимаются следующие опции:
-
-h,--help¶ показывает это справочное сообщение и завершает работу
-
-e,--exact¶ отображает имена токенов с использованием точного типа
Если указан filename.py, его содержимое токенизируется в stdout.
В противном случае токенизация выполняется из stdin.
32.7.3. Примеры¶Examples
Пример переписчика скриптов, преобразующего литералы чисел с плавающей запятой в объекты Decimal :
from tokenize import tokenize, untokenize, NUMBER, STRING, NAME, OP
from io import BytesIO
def decistmt(s):
"""Заменяет значения float на 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 ''