# 32.7. `tokenize` --- Pythonソースのためのトークナイザ

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

`tokenize` モジュールでは、Python で実装された Python ソースコードの字句解析器を提供します。さらに、このモジュールの字句解析器はコメントもトークンとして返します。このため、このモジュールはスクリーン上で表示する際の色付け機能 (colorizers) を含む "清書出力器 (pretty-printer)" を実装する上で便利です。

トークンストリームの扱いをシンプルにするために、全ての 演算子 (operator) と デリミタ (delimiter) トークンはジェネリックな `token.OP` トークンタイプとして返されます。正確な型は `tokenize.generate_tokens()` からの戻り値のタプルの 2 番目のフィールド (実際のマッチしたトークン文字列を含んでいます) を特定の演算子トークンを識別する文字シーケンスかチェックすれば決定出来ます。

第一のエントリポイントはジェネレータ(generator)です:

`tokenize.``generate_tokens`(readline)

  `generate_tokens()` ジェネレータは一つの引数 readline を必要とします。この引数は呼び出し可能オブジェクトで、組み込みファイルオブジェクトにおける `readline()` メソッドと同じインタフェースを提供していなければなりません (ファイルオブジェクト 節を参照してください)。この関数は呼び出しのたびに入力内の一行を文字列で返さなければなりません。もしくは、 readline を `StopIteration` を送出することで完了を知らせる呼び出し可能オブジェクトとすることもできます。

  このジェネレータは次の 5 要素のタプルを返します; トークンタイプ; トークン文字列; ソース内でそのトークンがどの行、列で開始するかを示す int の `(srow, scol)` タプル; どの行、列で終了するかを示す int の `(erow, ecol)` タプル; トークンが見つかった行。 (タプルの最後の要素にある) 行は 論理 行で、継続行が含まれます。

  バージョン 2.2 で追加.

後方互換性のために古いエントリポイントが残されています:

`tokenize.``tokenize`(readline[, tokeneater])

  `tokenize()` 関数は二つのパラメータを取ります: 一つは入力ストリームを表し、もう一つは `tokenize()` のための出力メカニズムを与えます。

  最初のパラメータ、 readline は、組み込みファイルオブジェクトの `readline()` メソッドと同じインタフェイスを提供する呼び出し可能オブジェクトでなければなりません ( ファイルオブジェクト 節を参照)。この関数は呼び出しのたびに入力内の一行を文字列で返さなければなりません。もしくは、 readline を `StopIteration` を送出することで完了を知らせる呼び出し可能オブジェクトとすることもできます。

  バージョン 2.5 で変更: `StopIteration` サポートの追加。

  二番目のパラメータ tokeneater も呼び出し可能オブジェクトでなければなりません。この関数は各トークンに対して一度だけ呼び出され、 `generate_tokens()` が生成するタプルに対応する 5 つの引数をとります。

`token` モジュールの全ての定数は `tokenize` でも公開されており、これに加え、以下の二つのトークン値が `tokenize()` の tokeneater 関数に渡される可能性があります:

`tokenize.``COMMENT`

  コメントであることを表すために使われるトークン値です。

`tokenize.``NL`

  終わりではない改行を表すために使われるトークン値。NEWLINE トークンは Pythonコードの論理行の終わりを表します。NLトークンはコードの論理行が複数の物理行にわたって続いているときに作られます。

もう一つの関数がトークン化プロセスを逆転するために提供されています。これは、スクリプトを字句解析し、トークンのストリームに変更を加え、変更されたスクリプトを書き戻すようなツールを作成する際に便利です。

`tokenize.``untokenize`(iterable)

  トークンの列を Python ソースコードに変換します。 iterable は少なくとも二つの要素、トークンタイプおよびトークン文字列、からなるシーケンスを返さなければいけません。 その他のシーケンスの要素は無視されます。

  再構築されたスクリプトは一つの文字列として返されます。得られる結果はもう一度字句解析すると入力と一致することが保証されるので、変換がロスレスでありラウンドトリップできることは間違いありません。この保証はトークン型およびトークン文字列に対してのものでトークン間のスペース (コラム位置)のようなものは変わることがあり得ます。

  バージョン 2.5 で追加.

exception `tokenize.``TokenError`

  docstring や複数行にわたることが許される式がファイル内のどこかで終わっていない場合に送出されます。例えば:

      """Beginning of
      docstring

  もしくは:

      [1,
       2,
       3

閉じていないシングルクォート文字列は送出されるべきエラーの原因とならないことに注意してください。それらは `ERRORTOKEN` とトークン化され、続いてその内容がトークン化されます。

スクリプト書き換えの例で、浮動小数点数リテラルを Decimal オブジェクトに変換します:

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

        >>> exec(s)
        -3.21716034272e-007
        >>> exec(decistmt(s))
        -3.217160342717258261933904529E-7

        """
        result = []
        g = generate_tokens(StringIO(s).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)