tokenize — Tokenizer for Python source

Вихідний код: Lib/tokenize.py


The tokenize module provides a lexical scanner for Python source code, implemented in Python. The scanner in this module returns comments as tokens as well, making it useful for implementing «pretty-printers», including colorizers for on-screen displays.

To simplify token stream handling, all operator and delimiter tokens and Ellipsis are returned using the generic OP token type. The TokenInfo.exact_type property gives the exact token type.

Попередження

Note that the functions in this module are only designed to parse syntactically valid Python code (code that does not raise when parsed using ast.parse()). The behavior of the functions in this module is undefined when providing invalid Python code and it can change at any point.

Tokenizing input

Основною точкою входу є generator:

tokenize.tokenize(readline)

Для генератора tokenize() потрібен один аргумент, readline, який має бути викликаним об’єктом, який забезпечує той самий інтерфейс, що й метод io.IOBase.readline() файлових об’єктів. Кожен виклик функції має повертати один рядок введення у вигляді байтів.

The generator produces TokenInfo objects.

Змінено в версії 3.1: Changed to yield TokenInfo objects instead of plain tuples.

tokenize() визначає вихідне кодування файлу, шукаючи специфікацію UTF-8 або кодування cookie, відповідно до PEP 263.

tokenize.generate_tokens(readline)

Токенізуйте джерело, яке читає рядки Unicode замість байтів.

Як і tokenize(), аргумент readline є викликом, що повертає один рядок введення. Однак generate_tokens() очікує, що readline повертатиме об’єкт str, а не байти.

The result is an iterator yielding TokenInfo objects, exactly like tokenize(). It does not yield an ENCODING token.

class tokenize.TokenInfo(type, string, start, end, line)

A named tuple describing a token. It has five fields and an additional exact_type property.

Added in version 3.1.

type

An integer identifying the token type, as defined by the constants in token, such as NAME and STRING. Operators and delimiters have type OP; use exact_type for their specific token type.

string

The token text as a str. For STRING tokens, this includes the quotes, any prefix, and escape sequences, without evaluating them.

For an ENCODING token, this is the encoding name. Tokens inserted without corresponding source text can have an empty string. In FSTRING_MIDDLE and TSTRING_MIDDLE tokens, doubled braces are replaced by single braces.

start

A 2-tuple (srow, scol) of ints specifying the inclusive start position of the token in the source. Rows are numbered from 1 and columns from 0. Columns count Unicode code points; a tab counts as one column, without expanding it to a tab stop.

For an ENCODING token, this is (0, 0).

end

A 2-tuple (erow, ecol) of ints specifying the exclusive end position of the token. Rows are numbered from 1 and columns from 0. For a token spanning multiple lines, erow is the final row and ecol is the column on that row.

For example, the name spam at the beginning of the first line has start equal to (1, 0) and end equal to (1, 4).

For an ENCODING token, this is (0, 0). A NEWLINE or NL token inserted at the end of input without a final newline can have an end column one beyond the source text.

line

A str containing the full source line on which the token was found, including surrounding text and the line terminator if present. For a token spanning multiple lines, this can contain several source lines. It is empty for ENCODING and ENDMARKER tokens.

exact_type

An integer identifying the specific operator type for OP tokens, as defined by the constants in token. For all other token types, this equals type. For example, a + token has type equal to OP and exact_type equal to PLUS.

Added in version 3.3.

All constants from the token module are also exported from tokenize.

Ще одна функція передбачена для зворотного процесу токенізації. Це корисно для створення інструментів, які токенізують сценарій, змінюють потік маркерів і записують назад змінений сценарій.

tokenize.untokenize(iterable)

Перетворює маркери назад у вихідний код Python. iterable має повертати послідовності принаймні з двома елементами, типом маркера та рядком маркера. Будь-які додаткові елементи послідовності ігноруються.

The result is guaranteed to tokenize back to match the input so that the conversion is lossless and round-trips are assured. The guarantee applies only to the token type and token string as the spacing between tokens (column positions) may change.

Він повертає байти, закодовані за допомогою маркера 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().

Added in version 3.2.

exception tokenize.TokenError

Викликається, коли рядок документа або вираз, які можуть бути розділені на кілька рядків, не завершені ніде у файлі, наприклад:

"""Beginning of
docstring

або:

[1,
 2,
 3

Command-line usage

Added in version 3.3.

The tokenize module can be executed as a script from the command line. It is as simple as:

python -m tokenize [-e] [filename.py]

Приймаються такі варіанти:

-h, --help

показати це довідкове повідомлення та вийти

-e, --exact

відображати імена токенів, використовуючи точний тип

Якщо вказано filename.py, його вміст токенізується до stdout. В іншому випадку токенізація виконується на stdin.

Added in version 3.15: Output is in color by default and can be controlled using environment variables.

Приклади

Приклад сценарію переписувача, який перетворює плаваючі літерали в десяткові об’єкти:

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()

will be tokenized to the following output where the first column is the range of the line/column coordinates where the token is found, the second column is the name of the token, and the final column is the value of the token (if any):

$ 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)