tokenize
— Tokenizer for Python source¶
Вихідний код: Lib/tokenize.py
Модуль tokenize
забезпечує лексичний сканер вихідного коду Python, реалізований на Python. Сканер у цьому модулі також повертає коментарі як токени, що робить його корисним для реалізації «красивих принтерів», включаючи розфарбовувачі для екранних дисплеїв.
Щоб спростити обробку потоку маркерів, усі маркери operator і delimiter і Ellipsis
повертаються за допомогою загального типу токена OP
. Точний тип можна визначити, перевіривши властивість exact_type
кортежу named tuple, який повертається з tokenize.tokenize()
.
Токенізований вхід¶
Основною точкою входу є generator:
-
tokenize.
tokenize
(readline)¶ Для генератора
tokenize()
потрібен один аргумент, readline, який має бути викликаним об’єктом, який забезпечує той самий інтерфейс, що й методio.IOBase.readline()
файлових об’єктів. Кожен виклик функції має повертати один рядок введення у вигляді байтів.Генератор створює 5-кортежі з такими членами: тип маркера; рядок маркера; 2-кортеж
(srow, scol)
int, що визначає рядок і стовпець, де починається маркер у джерелі; 2-кортеж(erow, ecol)
int, що визначає рядок і стовпець, де закінчується маркер у джерелі; і рядок, на якому було знайдено маркер. Пропущений рядок (останній елемент кортежу) є фізичним рядком. Кортеж 5 повертається як named tuple з іменами полів:type string start end line
.Повернений кортеж named tuple має додаткову властивість під назвою
exact_type
, яка містить точний тип оператора для токенівOP
. Для всіх інших типів токенівточний_тип
дорівнює іменованому полютип
кортежу.Змінено в версії 3.1: Додано підтримку іменованих кортежів.
Змінено в версії 3.3: Додано підтримку
exact_type
.tokenize()
визначає вихідне кодування файлу, шукаючи специфікацію UTF-8 або кодування cookie, відповідно до PEP 263.
-
tokenize.
generate_tokens
(readline)¶ Токенізуйте джерело, яке читає рядки Unicode замість байтів.
Як і
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
Note that unclosed single-quoted strings do not cause an error to be
raised. They are tokenized as ERRORTOKEN
, followed by the
tokenization of their contents.
Використання командного рядка¶
Нове в версії 3.3.
Модуль tokenize
можна запустити як скрипт із командного рядка. Це так просто:
python -m tokenize [-e] [filename.py]
Приймаються такі варіанти:
-
-h
,
--help
¶
показати це довідкове повідомлення та вийти
-
-e
,
--exact
¶
відображати імена токенів, використовуючи точний тип
Якщо вказано filename.py
, його вміст токенізується до stdout. В іншому випадку токенізація виконується на stdin.
Приклади¶
Приклад сценарію переписувача, який перетворює плаваючі літерали в десяткові об’єкти:
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 ''
Приклад токенізації файлу програмним шляхом, зчитування рядків Unicode замість байтів за допомогою 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)