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)ints, указывающий строку и столбец, где начинается маркер в источнике; 2-кортежный(erow, ecol)ints, указывающий строку и столбец, где маркер заканчивается в источнике; и строку, на которой был найден маркер. Переданная строка (последний элемент кортежа) - это физическая строка. 5 кортеж возвращенный как именованный кортеж с именами полей:type string start end line.У возвращенный именованный кортеж есть дополнительное свойство с именем
exact_type, содержащее точный тип оператора для маркеровOP. Для всех остальных типов маркеровexact_typeравно именованному полюtypeкортежа.Изменено в версии 3.1: Добавлена поддержка именованных кортежей.
Изменено в версии 3.3: Добавлена поддержка
exact_type.tokenize()определяет источник кодировка файла, ища BOM UTF-8 или печенье кодировки, согласно PEP 263.
-
tokenize.generate_tokens(readline)¶ Маркировать исходный строки Юникода вместо байтов.
Как и
tokenize(), аргумент readline является вызываемым, возвращающим одну строку ввода. Однакоgenerate_tokens()ожидает, что readline возвращает объект str, а не байты.В результате получается итератор, дающий именованные кортежи, точно как
tokenize(). Он не yield токенENCODING.
Все константы из модуля token также экспортируются из tokenize.
Предусмотрена еще одна функция для обращения процесса токенизации. Это полезно для создания инструментов для токенизации сценария, изменения потока маркеров и обратной записи измененного сценария.
-
tokenize.untokenize(iterable)¶ Преобразует маркеры обратно в исходный код Python. В iterable должны возвращает последовательности, содержащие по крайней мере два элемента, тип маркера и строка маркера. Любые дополнительные элементы последовательности игнорируются.
Реконструированный сценарий возвращенный как единый строка. Результат гарантированно получает токенизацию для соответствия входному сигналу, так что преобразование происходит без потерь и обеспечивается передача в оба конца. Гарантия применяется только к типу маркера и маркеру строка так как интервал между маркерами (позициями столбцов) может измениться.
Он возвращает байты, кодированный используя токен
ENCODING, который является первой последовательностью токенов, выводимойtokenize(). Если во входном файле нет маркера кодировка, он возвращает str.
tokenize() должен определить кодировку исходных файлов, которые он маркирует.
Функция, используемая для этого, доступна:
-
tokenize.detect_encoding(readline)¶ Функция
detect_encoding()используемый для обнаружения кодировка, которые должны быть используемый для декодирования исходного файла Python. Он требует одного аргумента, readline, так же, как иtokenize()генератор.Он вызовет readline максимум два раза, и возвращает кодировка используемый (как строка) и список любых строк (не декодированных из байтов), которые он прочитал.
Это обнаруживает кодировка от присутствия BOM UTF-8 или печенья кодировка, как определено в 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, его содержимое маркируется как stdout. В противном
случае токенизация выполняется на stdin.
Примеры¶
Пример переписчика сценария, преобразующего float литералы в десятичные объекты:
from tokenize import tokenize, untokenize, NUMBER, STRING, NAME, OP
from io import BytesIO
def decistmt(s):
"""Заменитm десятичные дроби на числа с плавающей точкой в строке операторов.
>>> 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
Выходные данные вычислений с десятичной запятой должны быть одинаковыми для всех
платформ.
>>> 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)
