# 29.2. `codeop` --- Pythonコードをコンパイルする

`codeop` モジュールは、 `code` モジュールで行われているようなPythonの read-eval-printループをエミュレートするユーティリティを提供します。そのため、このモジュールを直接利用する場面はあまり無いでしょう。プログラムにこのようなループを含めたい場合は、 `code` モジュールの方が便利です。

この仕事には二つの部分があります:

1. 入力の一行がPythonの文として完全であるかどうかを見分けられること: 簡単に言えば、次が '`>>>`' か、あるいは '`...`' かどうかを見分けます。
2. どのfuture文をユーザが入力したのかを覚えていること。したがって、実質的にそれに続く入力をこれらとともにコンパイルすることができます。

`codeop` モジュールはこうしたことのそれぞれを行う方法とそれら両方を行う方法を提供します。

前者は実行するには:

`codeop.``compile_command`(source[, filename[, symbol]])

  Pythonコードの文字列であるべき source をコンパイルしてみて、source が有効なPythonコードの場合はコードオブジェクトを返します。このような場合、コードオブジェクトのファイル名属性は、デフォルトで `'<input>'` である filename でしょう。source が有効なPythonコードでは ない が、有効なPythonコードの接頭語である場合には、`None` を返します。

  source に問題がある場合は、例外を発生させます。無効なPython構文がある場合は、 `SyntaxError` を発生させます。また、無効なリテラルがある場合は、 `OverflowError` または `ValueError` を発生させます。

  symbol 引数は source が文としてコンパイルされるか(`'single'` 、デフォルト) 、または 式 としてコンパイルされるかを決定します(`'eval'`)。他のどんな値も `ValueError` を発生させる原因となります。

  注釈

  ソースの終わりに達する前に、成功した結果をもってパーサは構文解析を止めることがあります。このような場合、後ろに続く記号はエラーとならずに無視されます。例えば、バックスラッシュの後ろに改行が2つあって、その後ろにゴミがあるかもしれません。パーサのAPIがより良くなればすぐに、この挙動は修正されるでしょう。

class `codeop.``Compile`

  このクラスのインスタンスは組み込み関数 `compile()` とシグネチャが一致する `__call__()` メソッドを持っていますが、インスタンスが `__future__` 文を含むプログラムテキストをコンパイルする場合は、インスタンスは有効なその文とともに続くすべてのプログラムテキストを'覚えていて'コンパイルするという違いがあります。

class `codeop.``CommandCompiler`

  このクラスのインスタンスは `compile_command()` とシグネチャが一致する `__call__()` メソッドを持っています。インスタンスが `__future__` 文を含むプログラムテキストをコンパイルする場合に、インスタンスは有効なその文とともにそれに続くすべてのプログラムテキストを'覚えていて'コンパイルするという違いがあります。

バージョン間の互換性についての注意: `Compile` と `CommandCompiler` はPython 2.2 で導入されました。2.2 の future-tracking 機能を有効にするだけでなく、 2.1 と Python のより以前のバージョンとの互換性も保ちたい場合は、次のように書くことができます

    try:
        from codeop import CommandCompiler
        compile_command = CommandCompiler()
        del CommandCompiler
    except ImportError:
        from codeop import compile_command

これは影響の小さい変更ですが、あなたのプログラムにおそらく望まれないグローバル状態を導入します。または、次のように書くこともできます:

    try:
        from codeop import CommandCompiler
    except ImportError:
        def CommandCompiler():
            from codeop import compile_command
            return compile_command

そして、新たなコンパイラオブジェクトが必要となるたびに `CommandCompiler` を呼び出します。