36.2. imp --- import 内部へのアクセス

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

バージョン 3.4 で非推奨: imp パッケージは importlib を後継として廃止予定です。


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

imp.get_magic()

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

バージョン 3.4 で非推奨: 代わりに importlib.util.MAGIC_NUMBER を使用してください。

imp.get_suffixes()

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

バージョン 3.3 で非推奨: 代わりに importlib.machinery で定義された定数を使ってください。

imp.find_module(name[, path])

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

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

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

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

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

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

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

バージョン 3.3 で非推奨: Use importlib.util.find_spec() instead unless Python 3.3 compatibility is required, in which case use importlib.find_loader().

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

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

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

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

バージョン 3.3 で非推奨: If previously used in conjunction with imp.find_module() then consider using importlib.import_module(), otherwise use the loader returned by the replacement you chose for imp.find_module(). If you called imp.load_module() and related functions directly then use the classes in importlib.machinery, e.g. importlib.machinery.SourceFileLoader(name, path).load_module().

imp.new_module(name)

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

バージョン 3.4 で非推奨: Use types.ModuleType instead.

imp.reload(module)

すでにインポートされた module を再解釈し、再初期化します。引数はモジュールオブジェクトでなければならないので、予めインポートに成功していなければなりません。この関数はモジュールのソースコードファイルを外部エディタで編集して、Python インタプリタから離れることなく新しいバージョンを試したい際に有効です。戻り値は (module 引数と同じ) モジュールオブジェクトです。

reload(module) を実行すると、以下の処理が行われます:

  • Python モジュールのコードは再コンパイルされ、モジュールレベルのコードは再度実行されます。モジュールの辞書中にある、何らかの名前に結び付けられたオブジェクトを新たに定義します。拡張モジュール中の init 関数が二度呼び出されることはありません。
  • Python における他のオブジェクトと同様、以前のオブジェクトのメモリ領域は、参照カウントがゼロにならないかぎり再利用されません。
  • モジュール名前空間内の名前は新しいオブジェクト (または更新されたオブジェクト) を指すよう更新されます。
  • 以前のオブジェクトが (外部の他のモジュールなどからの) 参照を受けている場合、それらを新たなオブジェクトに再束縛し直すことはないので、必要なら自分で名前空間を更新しなければなりません。

いくつか補足説明があります:

モジュールが再ロードされた際、その辞書 (モジュールのグローバル変数を含みます) はそのまま残ります。名前の再定義を行うと、以前の定義を上書きするので、一般的には問題はありません。新たなバージョンのモジュールが古いバージョンで定義された名前を定義していない場合、古い定義がそのまま残ります。辞書がグローバルテーブルやオブジェクトのキャッシュを維持していれば、この機能をモジュールを有効性を引き出すために使うことができます --- つまり、 try 文を使えば、必要に応じてテーブルがあるかどうかをテストし、その初期化を飛ばすことができます:

try:
    cache
except NameError:
    cache = {}

ビルトインのモジュールや動的にロードされたモジュールをリロードすることは、 sys, __main__, builtins を除いて一般にはそれほど有用ではありませんが、合法です。しかし、多くの場合、拡張モジュールは二度以上初期化されるようには作られておらず、リロードされた時に無作為な方法で失敗するかもしれません。

一方のモジュールが from ... import ... を使って、オブジェクトを他方のモジュールからインポートしているなら、他方のモジュールを reload() で呼び出しても、そのモジュールからインポートされたオブジェクトを再定義することはできません --- この問題を回避する一つの方法は、 from 文を再度実行することで、もう一つの方法は from 文の代わりに import と限定的な名前 (module.*name*) を使うことです。

あるモジュールがクラスのインスタンスを生成している場合、そのクラスを定義しているモジュールの再ロードはそれらインスタンスのメソッド定義に影響しません --- それらは古いクラス定義を使い続けます。これは派生クラスの場合でも同じです。

バージョン 3.3 で変更: リロードされるモジュール上で、__name__ だけでなく __name____loader__ の両方が定義されていることに依存します。

バージョン 3.4 で非推奨: 代わりに importlib.reload() を使用してください。

以下は、 PEP 3147 のバイトコンパイルされたファイルパスを扱うために便利な関数です。

バージョン 3.2 で追加.

imp.cache_from_source(path, debug_override=None)

ソース path に関連付けられたバイトコンパイルされたファイルの PEP 3147 パスを返します。例えば、 path/foo/bar/baz.py なら、 Python 3.2 の場合返り値は /foo/bar/__pycache__/baz.cpython-32.pyc になります。 cpython-32 という文字列は、現在のマジックタグから得られます (マジックタグについては get_tag() を参照; sys.implementation.cache_tag が未定義なら NotImplementedError が送出されます)。 debug_overrideTrue あるいは False を渡すことによって、 __debug__ システム値をオーバーライドして最適化されたバイトコードを得ることができます。

path は存在している必要はありません。

バージョン 3.3 で変更: sys.implementation.cache_tagNone の場合、 NotImplementedError が上げられます。

バージョン 3.4 で非推奨: 代わりに importlib.util.cache_from_source() を使用してください。

バージョン 3.5 で変更: debug_override 引数は .pyo ファイルを作成することはもうありません。

imp.source_from_cache(path)

PEP 3147 ファイル名への path が与えられると、関連するソースコードのファイルパスを返します。例えば、 path/foo/bar/__pycache__/baz.cpython-32.pyc なら、返されるパスは /foo/bar/baz.py になります。 path は存在する必要はありませんが、 PEP 3147 フォーマットに一致しない場合は ValueError が送出されます。 sys.implementation.cache_tag が定義されていない場合、 NotImplementedError が送出されます。

バージョン 3.3 で変更: sys.implementation.cache_tag が定義されていない場合、 NotImplementedError が上げられます。

バージョン 3.4 で非推奨: 代わりに importlib.util.source_from_cache() を使用してください。

imp.get_tag()

get_magic() によって返されるのと同じ、このバージョンの Python のマジックナンバーと一致する PEP 3147 のマジックタグ文字列を返します。

バージョン 3.4 で非推奨: Python 3.3 からは sys.implementation.cache_tag を直接使ってください。

以下の関数はインポートシステムの内部ロックメカニズムとのやりとりをサポートします。インポートのロックセマンティクスはリリース毎に変わる可能性のある実装詳細です。ただし、Python は循環インポートがデッドロックなしで動作することを保証しています。

imp.lock_held()

現在グローバルなインポートロックが保持されている場合 True を返し、そうでなければ False を返します。スレッドのないプラットフォームでは常に False を返します。

スレッドを持つプラットフォームでは、まずインポートを実行するスレッドがグローバルなインポートロックを保持し、次にインポートの残りの部分を実行するためにモジュール単位のロックをセットアップします。これは、他のスレッドが同じモジュールをインポートするのをオリジナルのインポートが完了するまでブロックして、他のスレッドがオリジナルのスレッドによって構築された不完全なモジュールオブジェクトを見てしまわないようにします。循環インポートに対しては例外が発生します。これは、そのようなモジュールを構築するためには、どこかの時点で不完全なモジュールオブジェクトを露出しなければならないためです。

バージョン 3.3 で変更: ロックスキームは、大部分がモジュール毎のロックに変わりました。グローバルなインポートロックは、モジュール毎のロックを初期化するようないくつかのクリティカルタスクのために維持されます。

バージョン 3.4 で非推奨.

imp.acquire_lock()

現在のスレッドに対するインタープリタのグローバルなインポートロックを獲得します。このロックは、モジュールをインポートする際にスレッドセーフ性を保証するために、インポートフックによって使用されるべきです。

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

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

バージョン 3.3 で変更: ロックスキームは、大部分がモジュール毎のロックに変わりました。グローバルなインポートロックは、モジュール毎のロックを初期化するようないくつかのクリティカルタスクのために維持されます。

バージョン 3.4 で非推奨.

imp.release_lock()

インタープリタのグローバルなインポートロックを解放します。スレッドのないプラットフォームでは何もしません。

バージョン 3.3 で変更: ロックスキームは、大部分がモジュール毎のロックに変わりました。グローバルなインポートロックは、モジュール毎のロックを初期化するようないくつかのクリティカルタスクのために維持されます。

バージョン 3.4 で非推奨.

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

imp.PY_SOURCE

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

バージョン 3.3 で非推奨.

imp.PY_COMPILED

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

バージョン 3.3 で非推奨.

imp.C_EXTENSION

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

バージョン 3.3 で非推奨.

imp.PKG_DIRECTORY

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

バージョン 3.3 で非推奨.

imp.C_BUILTIN

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

バージョン 3.3 で非推奨.

imp.PY_FROZEN

モジュールが frozen モジュールとして発見された。

バージョン 3.3 で非推奨.

class imp.NullImporter(path_string)

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

インスタンスはたった一つのメソッドを持ちます:

find_module(fullname[, path])

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

バージョン 3.3 で変更: NullImporter のインスタンスの代わりに Nonesys.path_importer_cache に挿入されます。

バージョン 3.4 で非推奨: 代わりに Nonesys.path_importer_cache に挿入してください。

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