tokenize
— Токенизатор для исходного кода Python¶
Исходный код: Lib/tokenize.py
Модуль tokenize
предоставляет лексический сканер для исходного кода Python, реализованный на Python. Сканер в этом модуле также возвращает комментарии в виде токенов, что делает его полезным для реализации «симпатичных принтеров», включая средства раскрашивания для экранных дисплеев.
Чтобы упростить обработку потока токенов, все токены operator и delimiter, а также Ellipsis
возвращаются с использованием универсального типа токена OP
. Точный тип можно определить, проверив свойство exact_type
в named tuple, возвращаемое из tokenize.tokenize()
.
Предупреждение
Обратите внимание, что функции в этом модуле предназначены только для синтаксического анализа кода на Python (кода, который не генерируется при анализе с использованием ast.parse()
). Поведение функций в этом модуле не определено при предоставлении недопустимого кода на Python и может измениться в любой момент.
Ввод токенов¶
Основной точкой входа является generator:
- tokenize.tokenize(readline)¶
Генератору
tokenize()
требуется один аргумент, readline, который должен быть вызываемым объектом, предоставляющим тот же интерфейс, что и методio.IOBase.readline()
для файловых объектов. Каждый вызов функции должен возвращать одну строку ввода в виде байтов.Генератор генерирует 5 кортежей со следующими элементами: тип токена; строка токена; 2 кортежа
(srow, scol)
из целых чисел, указывающих строку и столбец, с которых начинается токен в источнике; 2 кортежа(erow, ecol)
из целых чисел, указывающих строку и столбец, в котором заканчивается токен в источнике; и строка, в которой был найден токен. Переданная строка (последний элемент кортежа) является физической строкой. Кортеж 5 возвращается в виде named tuple с именами полей:type string start end line
.Возвращаемое значение named tuple содержит дополнительное свойство с именем
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 вернет объект str, а не байты.Результатом является итератор, выдающий именованные кортежи, точно такие же, как
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¶
Возникает, когда строка документа или выражение, которые могут быть разделены на несколько строк, нигде в файле не заполнены, например:
"""Beginning of docstring
или:
[1, 2, 3
Обратите внимание, что незакрытые строки, заключенные в одинарные кавычки, не приводят к возникновению ошибки. Они обозначаются как ERRORTOKEN
, за которыми следует символизация их содержимого.
Использование командной строки¶
Добавлено в версии 3.3.
Модуль tokenize
может быть запущен в виде скрипта из командной строки. Это так же просто, как:
python -m tokenize [-e] [filename.py]
Принимаются следующие варианты:
- -h, --help¶
отобразите это справочное сообщение и закройте
- -e, --exact¶
отображать имена токенов, используя точный тип
Если указано значение filename.py
, то его содержимое преобразуется в стандартный вывод. В противном случае токенизация выполняется в стандартном вводе.
Примеры¶
Пример перезаписи скрипта, который преобразует литералы с плавающей точкой в десятичные объекты:
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 ''
Пример программной маркировки файла с использованием строк юникода вместо байтов с 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)