# 31.1. `imp` --- `import` 内部へアクセスする

このモジュールは `import` 文を実装するために使われているメカニズムへのインターフェイスを提供します。次の定数と関数が定義されています:

`imp.``get_magic`()

  バイトコンパイルされたコードファイル(`.pyc` ファイル)を認識するために使われるマジック文字列値を返します。 (この値は Python の各バージョンで異なります。)

`imp.``get_suffixes`()

  3要素のタプルのリストを返します。それぞれのタプルは特定の種類のモジュールを説明しています。各タプルは `(suffix, mode, type)` という形式です。ここで、 suffix は探すファイル名を作るためにモジュール名に追加する文字列です。そのファイルをオープンするために、 mode は組み込み `open()` 関数へ渡されるモード文字列です (これはテキストファイル対しては `'r'` 、バイナリファイルに対しては `'rb'` となります)。 type はファイル型で、以下で説明する値 `PY_SOURCE`, `PY_COMPILED` あるいは、 `C_EXTENSION` の一つを取ります。

`imp.``find_module`(name[, path])

  モジュール name を見つけようとします。 path が省略されるか `None` ならば、 `sys.path` によって与えられるディレクトリ名のリストが検索されます。しかし、最初にいくつか特別な場所を検索します。まず、所定の名前をもつ組み込みモジュール(`C_BUILTIN`)を見つけようとします。それから、フリーズされたモジュール(`PY_FROZEN`)、そしていくつかのシステムでは他の場所が同様に検索されます (Windowsでは、特定のファイルを指すレジストリの中を見ます)。

  それ以外の場合、 path はディレクトリ名のリストでなければなりません。上の `get_suffixes()` が返す拡張子のいずれかを伴ったファイルを各ディレクトリの中で検索します。リスト内の有効でない名前は黙って無視されます(しかし、すべてのリスト項目は文字列でなければなりません)。

  検索が成功すれば、戻り値は3要素のタプル `(file, pathname, description)` です:

  file は先頭に位置合わせされたオープンファイルオブジェクトで、 pathname は見つかったファイルのパス名です。そして、 description は `get_suffixes()` が返すリストに含まれているような3要素のタプルで、見つかったモジュールの種類を説明しています。

  モジュールがファイルとして存在していなければ、返された file は `None` で、 pathname は空文字列、 description タプルはその拡張子とモードに対して空文字列を含みます。モジュール型は上の括弧の中に示されます。検索が失敗すれば、 `ImportError` が発生します。他の例外は引数または環境に問題があることを示唆します。

  モジュールがパッケージならば、 file は `None` で、 pathname はパッケージのパスで description タプルの最後の項目は `PKG_DIRECTORY` です。

  この関数は階層的なモジュール名(ドットを含む名前)を扱いません。 P.M 、すなわちパッケージ P のサブモジュール M を見つけるためには、まず `find_module()` と `load_module()` を使用してパッケージ P を見つけてロードして、次に `P.__path__` を path 引数にして `find_module()` を呼び出してください。もし P 自体がドット付きの名前を持つ場合、このレシピを再帰的に適用してください。

`imp.``load_module`(name, file, pathname, description)

  `find_module()` を使って(あるいは、互換性のある結果を作り出す検索を行って)以前見つけたモジュールをロードします。この関数はモジュールをインポートするという以上のことを行います: モジュールが既にインポートされているならば、 `reload()` と同じです! name 引数は(これがパッケージのサブモジュールならばパッケージ名を含む)完全なモジュール名を示します。 file 引数はオープンしたファイルで、 pathname は対応するファイル名です。モジュールがパッケージであるかファイルからロードされようとしていないとき、これらはそれぞれ `None` と `''` であっても構いません。 `get_suffixes()` が返すように description 引数はタプルで、どの種類のモジュールがロードされなければならないかを説明するものです。

  ロードが成功したならば、戻り値はモジュールオブジェクトです。そうでなければ、例外(たいていは `ImportError`)が発生します。

  重要: file 引数が `None` でなければ、例外が発生した場合でも呼び出し側にはそれを閉じる責任があります。これを行うには、 `try` ... `finally` 文を使うことが最も良いです。

`imp.``new_module`(name)

  name という名前の新しい空モジュールオブジェクトを返します。このオブジェクトは `sys.modules` に挿入され ません 。

`imp.``lock_held`()

  現在インポートロックが維持されているならば、 `True` を返します。そうでなければ、 `False` を返します。スレッドのないプラットホームでは、常に `False` を返します。

  スレッドのあるプラットホームでは、インポートが完了するまでインポートを実行するスレッドは内部ロックを維持します。このロックは元のインポートが完了するまで他のスレッドがインポートすることを阻止します。言い換えると、元のスレッドがそのインポート(および、もしあるならば、それによって引き起こされるインポート) の途中で構築した不完全なモジュールオブジェクトを、他のスレッドが見られないようにします。

`imp.``acquire_lock`()

  実行中のスレッドでインタープリタのインポートロックを取得します。インポートフックは、スレッドセーフのためにこのロックを取得しなければなりません。

  一旦スレッドがインポートロックを取得したら、その同じスレッドはブロックされることなくそのロックを再度取得できます。スレッドはロックを取得するのと同じだけ解放しなければなりません。

  スレッドのないプラットホームではこの関数は何もしません。

  バージョン 2.3 で追加.

`imp.``release_lock`()

  インタープリタのインポートロックを解放します。スレッドのないプラットホームではこの関数は何もしません。

  バージョン 2.3 で追加.

整数値をもつ次の定数はこのモジュールの中で定義されており、 `find_module()` の検索結果を表すために使われます。

`imp.``PY_SOURCE`

  ソースファイルとしてモジュールが発見された。

`imp.``PY_COMPILED`

  コンパイルされたコードオブジェクトファイルとしてモジュールが発見された。

`imp.``C_EXTENSION`

  動的にロード可能な共有ライブラリとしてモジュールが発見された。

`imp.``PKG_DIRECTORY`

  パッケージディレクトリとしてモジュールが発見された。

`imp.``C_BUILTIN`

  モジュールが組み込みモジュールとして発見された。

`imp.``PY_FROZEN`

  モジュールがフリーズされたモジュールとして発見された(`init_frozen()` を参照)。

以下の定数と関数は旧バージョンのものです。 `find_module()` や `load_module()` を使えば同様の機能を利用できます。これらは後方互換性のために残されています:

`imp.``SEARCH_ERROR`

  使われていません。

`imp.``init_builtin`(name)

  name という名前の組み込みモジュールを初期化し、そのモジュールオブジェクトを `sys.modules` に格納した上で返します。モジュールが既に初期化されている場合は、 再度 初期化されます。再初期化は組み込みモジュールの `__dict__` を `sys.modules` のエントリーに結びつけられたキャッシュモジュールからコピーする過程を含みます。 name という名前の組み込みモジュールがない場合は、 `None` を返します。

`imp.``init_frozen`(name)

  name という名前のフリーズされたモジュールを初期化し、モジュールオブジェクトを返します。モジュールが既に初期化されている場合は、 再度 初期化されます。 name という名前のフリーズされたモジュールがない場合は、 `None` を返します。 (フリーズされたモジュールは Python で書かれたモジュールで、そのコンパイルされたバイトコードオブジェクトが Python の freeze ユーティリティを使ってカスタムビルド版の Python インタープリタへ組み込まれています。差し当たり、 `Tools/freeze/` を参照してください。)

`imp.``is_builtin`(name)

  name という名前の再初期化できる組み込みモジュールがある場合は、 `1` を返します。 name という名前の再初期化できない組み込みモジュールがある場合は、 `-1` を返します (`init_builtin()` を参照してください)。 name という名前の組み込みモジュールがない場合は、 `0` を返します。

`imp.``is_frozen`(name)

  name という名前のフリーズされたモジュール(`init_frozen()` を参照)がある場合は、 `True` を返します。または、そのようなモジュールがない場合は、 `False` を返します。

`imp.``load_compiled`(name, pathname[, file])

  バイトコンパイルされたコードファイルとして実装されているモジュールをロードして初期化し、そのモジュールオブジェクトを返します。モジュールが既に初期化されている場合は、 再度 初期化されます。 name 引数はモジュールオブジェクトを作ったり、アクセスするために使います。 pathname 引数はバイトコンパイルされたコードファイルを指します。 file 引数はバイトコンパイルされたコードファイルで、バイナリモードでオープンされ、先頭からアクセスされます。現在は、ユーザ定義のファイルをエミュレートするクラスではなく、実際のファイルオブジェクトでなければなりません。

`imp.``load_dynamic`(name, pathname[, file])

  動的ロード可能な共有ライブラリとして実装されているモジュールをロードして初期化します。モジュールが既に初期化されている場合は、 再度 初期化します。再初期化はモジュールのキャッシュされたインスタンスの `__dict__` 属性を `sys.modules` にキャッシュされたモジュールの中で使われた値に上書きコピーする過程を含みます。 pathname 引数は共有ライブラリを指していなければなりません。 name 引数は初期化関数の名前を作るために使われます。共有ライブラリの `initname()` という名前の外部C関数が呼び出されます。オプションの file 引数は無視されます。 (注意: 共有ライブラリはシステムに大きく依存します。また、すべてのシステムがサポートしているわけではありません。)

  インポートの内部処理は拡張モジュールをファイル名で識別します。ですから `foo = load_dynamic("foo", "mod.so")` と `bar = load_dynamic("bar", "mod.so")` では foo と bar のどちらも同じモジュールを参照します。 `mod.so` が `initbar` 関数を公開しているかどうかに無関係にです。シンボリックリンクをサポートするシステムでも、それをすると、各々のモジュール参照が異なったファイル名を使って同じ共有ライブラリからの多重インポートになりえます。

`imp.``load_source`(name, pathname[, file])

  Python ソースファイルとして実装されているモジュールをロードして初期化し、モジュールオブジェクトを返します。モジュールが既に初期化されている場合は、 再度 初期化します。 name 引数はモジュールオブジェクトを作成したり、アクセスしたりするために使われます。 pathname 引数はソースファイルを指します。 file 引数はソースファイルで、テキストとして読み込むためにオープンされ、先頭からアクセスされます。現在は、ユーザ定義のファイルをエミュレートするクラスではなく、実際のファイルオブジェクトでなければなりません。 (拡張子 `.pyc` または `.pyo` をもつ)正しく対応するバイトコンパイルされたファイルが存在する場合は、与えられたソースファイルを構文解析する代わりにそれが使われることに注意してください。

class `imp.``NullImporter`(path_string)

  `NullImporter` 型は PEP 302 インポートフックで、何もモジュールが見つからなかったときの非ディレクトリパス文字列を処理します。この型を既存のディレクトリや空文字列に対してコールすると `ImportError` が発生します。それ以外の場合は `NullImporter` のインスタンスが返されます。

  Python は、ディレクトリでなく `sys.path_hooks` のどのパスフックでも処理されていないすべてのパスエントリに対して、この型のインスタンスを `sys.path_importer_cache` に追加します。このインスタンスが持つメソッドは次のひとつです。

  `find_module`(fullname[, path])

    このメソッドは常に `None` を返し、要求されたモジュールが見つからなかったことを表します。

  バージョン 2.5 で追加.

## 31.1.1. 例

次の関数は Python 1.4 までの標準 import 文(階層的なモジュール名がない)をエミュレートします。 (この 実装 はそのバージョンでは動作しないでしょう。なぜなら、 `find_module()` は拡張されており、また `load_module()` が 1.4 で追加されているからです。)

    import imp
    import sys

    def __import__(name, globals=None, locals=None, fromlist=None):
        # Fast path: see if the module has already been imported.
        try:
            return sys.modules[name]
        except KeyError:
            pass

        # If any of the following calls raises an exception,
        # there's a problem we can't handle -- let the caller handle it.

        fp, pathname, description = imp.find_module(name)

        try:
            return imp.load_module(name, fp, pathname, description)
        finally:
            # Since we may exit via an exception, close fp explicitly.
            if fp:
                fp.close()

階層的なモジュール名を実装し、 `reload()` 関数を含むより完全な例はモジュール `knee` にあります。 `knee` モジュールは Python のソースディストリビューションの中の `Demo/imputil/` にあります。