tokenize — PythonソースのTokenizer —Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/library/tokenize
移動先:案内検索

tokenize —Pythonソースのトークナイザー

ソースコード: :source: `Lib / tokenize.py`



tokenize モジュールは、Pythonで実装されたPythonソースコードの字句スキャナーを提供します。 このモジュールのスキャナーはコメントもトークンとして返すため、オンスクリーンディスプレイ用のカラーライザーなどの「プリティプリンター」の実装に役立ちます。

トークンストリームの処理を簡素化するために、すべての operator および delimiter トークンと Ellipsis は、汎用の OP トークンタイプを使用して返されます。 正確なタイプは、 tokenize.tokenize()から返された名前付きタプルexact_typeプロパティを確認することで判別できます。

入力のトークン化

プライマリエントリポイントはジェネレータです。

tokenize.tokenize(readline)

tokenize()ジェネレーターには、 readline という1つの引数が必要です。これは、 io.IOBase.readline()メソッドと同じインターフェイスを提供する呼び出し可能なオブジェクトである必要があります。ファイルオブジェクトの。 関数を呼び出すたびに、1行の入力がバイトとして返されます。

ジェネレータは、次のメンバーで5つのタプルを生成します。トークンタイプ。 トークン文字列。 ソースでトークンが始まる行と列を指定するintの2タプル(srow, scol)。 トークンがソースで終了する行と列を指定するintの2タプル(erow, ecol)。 トークンが見つかった行。 渡された行(最後のタプル項目)は、物理行です。 5タプルは、フィールド名がtype string start end line名前付きタプルとして返されます。

返されたという名前のタプルには、 OP トークンの正確な演算子タイプを含むexact_typeという名前の追加のプロパティがあります。 他のすべてのトークンタイプの場合、exact_typeは名前付きタプルtypeフィールドと同じです。

バージョン3.1で変更:名前付きタプルのサポートが追加されました。

バージョン3.3で変更: exact_typeのサポートが追加されました。

tokenize()は、 PEP 263 に従って、UTF-8 BOMまたはエンコーディングCookieを検索することにより、ファイルのソースエンコーディングを決定します。

tokenize.generate_tokens(readline)

バイトの代わりにUnicode文字列を読み取るソースをトークン化します。

tokenize()と同様に、 readline 引数は、1行の入力を返す呼び出し可能です。 ただし、 generate_tokens()は、 readline がバイトではなくstrオブジェクトを返すことを想定しています。

その結果、 tokenize()とまったく同じように、名前付きタプルを生成するイテレータが生成されます。 ENCODING トークンは生成されません。

token モジュールのすべての定数は、 tokenize からもエクスポートされます。

トークン化プロセスを逆にするための別の関数が提供されています。 これは、スクリプトをトークン化し、トークンストリームを変更し、変更されたスクリプトを書き戻すツールを作成する場合に役立ちます。

tokenize.untokenize(iterable)

トークンをPythonソースコードに変換し直します。 iterable は、トークンタイプとトークン文字列の少なくとも2つの要素を持つシーケンスを返す必要があります。 追加のシーケンス要素は無視されます。

再構築されたスクリプトは、単一の文字列として返されます。 結果は、入力に一致するようにトークン化されることが保証されているため、変換はロスレスであり、ラウンドトリップが保証されます。 トークン間の間隔(列の位置)が変更される可能性があるため、保証はトークンタイプとトークン文字列にのみ適用されます。

ENCODING トークンを使用してエンコードされたバイトを返します。これは、 tokenize()によって出力される最初のトークンシーケンスです。 入力にエンコーディングトークンがない場合は、代わりにstrを返します。

tokenize()は、トークン化するソースファイルのエンコーディングを検出する必要があります。 これを行うために使用する機能が利用可能です:

tokenize.detect_encoding(readline)

detect_encoding()関数は、Pythonソースファイルのデコードに使用する必要のあるエンコーディングを検出するために使用されます。 tokenize()ジェネレーターと同じように、1つの引数readlineが必要です。

readlineを最大2回呼び出し、使用されたエンコーディング(文字列として)と、読み込んだ行のリスト(バイトからデコードされていない)を返します。

PEP 263 で指定されているUTF-8BOMまたはエンコーディングCookieの存在からエンコーディングを検出します。 BOMとCookieの両方が存在するが、同意しない場合、 SyntaxError が発生します。 BOMが見つかった場合、'utf-8-sig'がエンコーディングとして返されることに注意してください。

エンコーディングが指定されていない場合、デフォルトの'utf-8'が返されます。

open()を使用してPythonソースファイルを開きます。 detect_encoding()を使用してファイルエンコーディングを検出します。

tokenize.open(filename)

detect_encoding()で検出されたエンコーディングを使用して、読み取り専用モードでファイルを開きます。

バージョン3.2の新機能。

exception tokenize.TokenError

数行に分割される可能性のあるdocstringまたは式のいずれかが、ファイルのどこにも完了していない場合に発生します。次に例を示します。

"""Beginning of
docstring

or:

[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.


Command-Line Usage

New 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]

The following options are accepted:

-h, --help
show this help message and exit
-e, --exact
display token names using the exact type

If filename.py is specified its contents are tokenized to stdout. Otherwise, tokenization is performed on stdin.


Examples

Example of a script rewriter that transforms float literals into Decimal objects:

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

Example of tokenizing from the command line. The script:

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      ''

The exact token type names can be displayed using the -e option:

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

Example of tokenizing a file programmatically, reading unicode strings instead of bytes with generate_tokens():

import tokenize

with tokenize.open('hello.py') as f:
    tokens = tokenize.generate_tokens(f.readline)
    for token in tokens:
        print(token)

Or reading bytes directly with tokenize():

import tokenize

with open('hello.py', 'rb') as f:
    tokens = tokenize.tokenize(f.readline)
    for token in tokens:
        print(token)