読者です 読者をやめる 読者になる 読者になる

__import__

Python

Pythonを使い始めた時、「動的にモジュールをインポートする(実行時にインポートするモジュールを決定する)にはどうすればいいんだろう」と疑問に思っていたのですが、組み込み関数の__import__を使えばできます。例えば、spam.eggモジュールを読み込みには、

module = __import__('spam.egg', globals(), locals(), [])

とすればOK。ただし、こうやって読み込んだだけでは、モジュール内の名前を参照することができないので、getattr関数などを使って適宜参照する必要があると思います。例えば、spam.eggモジュールのham関数を参照するならば、次の通り。

ham = getattr(module, 'ham')
ham()

ここまでは、公式のライブラリ・リファレンスを読めば分かることで、僕が今までよく理解していなかったのは次の二つ。

  • __import__の第二引数、第三引数に与えているglobals(), locals()は何に使われているのか?
  • __import__は、呼び出すたびにモジュールの再読み込みを行うのか?


最初の疑問に対しては、リファレンスに、

標準の実装では locals 引数を全く使わず、import 文のパッケージ文脈を決定するためだけに globals を使います。

と書かれていて、ある程度は推測できるのですが、この辺りの処理を行っているソースコード(Python/import.c)を読むとはっきりと理解できます。これはつまり、

- spam
-- __init__.py
-- util.py
- util.py

というモジュール構造になっている場合に、spam/__init__.pyで、

import util

と書いたとすると、spam/util.pyとutil.pyのどちらのutil.pyがインポートされるかを決定するために使われるということですね。つまり、この場合は、相対インポートの規則にのっとって、spam/util.pyがインポートされます。
ちなみに、Djangoのソースコードでは、実行時にモジュールを読み込む方法として、一貫して、

module = __import__(module_name, {}, {}, [])

という書き方がされています。あまり配慮せずに書くと、第二引数以下を省略して、

module = __import__(module_name)

でもいいはずですが、この場合は絶対インポート(absolute import)を強制するために、こう書いているのだと思います。違うかもしれない・・・、何のためにわざわざ引数指定してるんだろ・・・明示的に書きたいというだけ??


第二の疑問「__import__は呼び出すたびにモジュールの再読み込みを行うのか」についても、結論から先に言うと、「同じ名前のモジュールは一度しか読み込まない」ということが分かりました。
これはソースを読まなくても、次のような簡単なテストコードを書いてみれば分かります。

# spam.py
print "Imported"
# -*- coding: utf-8 -*-
# importtest.py
# 上のspam.pyと同じディレクトリに配置します
mod = __import__("spam", {}, {}, [])
mod = __import__("spam", {}, {}, [])

コマンドラインから実行すると、一度しか"Imported"と表示されないはずです。__import__関数を使ってモジュールを読み込んだとしても、すなわち、普通のimport文と同じく、最初の一回しか読み込みがおこなわれません。(再読み込みを行いたい場合はreload関数を使う必要があります。)

$ python importtest.py
Imported

まとめ

include($module_name), include_once($module_name)でモジュールを実行時に読み込めるPHPは最強。