モジュールの動的インポート

__import__()関数を使うと、モジュールを動的にインポートでき、コードの途中でインポートすることができます。例えば、


np = __import__("numpy")
np.random.rand()

# 0.2112903121866424

といったように。
普段あまり意識しませんが、numpyをインポートしているのにnumpy.randomが使えるのは、モジュールのトップレベルであるnumpyをインポートすると下位のモジュールのnumpy.randomも自動的にインポートされるからです。

xml.etree.ElementTreeの問題

しかしXMLを解析するモジュールであるxmlのサブモジュールxml.etree.ElementTreeを使おうと思って、この方法でxmlを動的にインポートするとエラーが出ます。


xml = __import__("xml")
xml_text = "<data> ナイスなデータ </data>"
root = xml.etree.ElementTree.fromstring(xml_text)

# TypeError: 'module' object is not callable

xmlにおいては、トップモジュールであるxmlをインポートしてもサブモジュールは自動でインポートされないようです。

さらに、__import__()関数は下位モジュールを指定してもトップモジュールをインポートします(参考:__import__のドキュメント)。つまりこうすることはできません。


ET = __import__("xml.etree.ElementTree")
xml_text = "<data> ナイスなデータ </data>"
root = ET.fromstring(xml_text)

# TypeError: 'module' object is not callable

このコードでは、上のコードと同様に変数ET内にはトップモジュールのxmlが入っています。

解決法

__import__()関数のドキュメントの注記にもあるように、__import__()関数ではなく、標準モジュールimportlibのimport_module()を使うことが推奨されているようです。


import importlib
ET = importlib.import_module("xml.etree.ElementTree")
xml_text = "<data> ナイスなデータ </data>"
root = ET.fromstring(xml_text)

importlibのドキュメントにも

import_module() 関数は importlib.__import__() を単純化するラッパーとして働きます。つまり、この関数のすべての意味は importlib.__import__() から受け継いでいます。これらの2つの関数の最も重要な違いは、 import_module() が指定されたパッケージやモジュール (例えば pkg.mod) を返すのに対し、__import__() はトップレベルのパッケージやモジュール (例えば pkg) を返すことです。

という記述があり(機械翻訳による)、import_moduleはサブモジュールを呼び出すための関数のようです。