tokenize — Токенизатор для исходного кода Python
Исходный код: Lib/tokenize.py
Модуль tokenize предоставляет лексический анализатор для исходного кода Python, реализованный на Python. Анализатор в этом модуле возвращает комментарии как токены, что делает его полезным для реализации "красивых принтеров", включая колоризаторы для отображения на экране.
Для упрощения обработки потока токенов все операторы и разделители возвращаются с использованием универсального типа токена token.OP. Точный тип можно определить, проверив свойство exact_type на именованном кортеже, возвращаемом из tokenize.tokenize().
1. Токенизация входных данных
Основной точкой входа является генератор:
-
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()определяет кодировку исходного файла, просматривая BOM UTF-8 или кодировочные куки, согласно 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, за которым следует токенизация их содержимого.
2. Использование в командной строке
Введено в версии 3.3.
Модуль tokenize может выполняться как скрипт из командной строки. Это так же просто, как:
python -m tokenize [-e] [filename.py]
Принимаются следующие параметры:
-
-h, --help -
отобразить это сообщение справки и завершить выполнение
-
-e, --exact -
отобразить имена токенов с использованием точного типа
Если filename.py указан, его содержимое токенизируется в стандартный вывод. В противном случае, токенизация выполняется на стандартном вводе.
3. Примеры
Пример скрипта-переработчика, который преобразует литералы float в объекты 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 ''
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.5/library/tokenize.html