1. ホーム
  2. python

[解決済み] モジュール名を文字列で指定してインポートするには?

2022-03-16 15:34:56

質問

Pythonで、例えばコマンドを引数に取るようなアプリケーションを書いています。

$ python myapp.py command1

私はこのアプリケーションを拡張可能なものにしたいのです。つまり、メインのアプリケーションのソースを変更することなく、新しいコマンドを実装する新しいモジュールを追加できるようにしたいのです。ツリーは以下のような感じです。

myapp/
    __init__.py
    commands/
        __init__.py
        command1.py
        command2.py
    foo.py
    bar.py

そこで、アプリケーションは実行時に利用可能なコマンドモジュールを見つけ、適切なものを実行するようにしたいのです。

Pythonでは __import__ 関数は、モジュール名を文字列で受け取ります。

__import__(name, globals=None, locals=None, fromlist=(), level=0)

この関数はモジュール名をインポートし、パッケージコンテキストでその名前をどのように解釈するかを決定するために、与えられたグローバルとローカルを潜在的に使用します。fromlist は、名前で与えられたモジュールからインポートされるべきオブジェクトまたはサブモジュールの名前を与えます。

出典 https://docs.python.org/3/library/functions.html# インポート

だから現在、私は次のようなものを持っています。

command = sys.argv[1]
try:
    command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
    # Display error message

command_module.run()

ただ、このコードでやっていることを達成するために、もっと簡単な方法があるのではないかと思っています。

なお、私は特に卵や拡張ポイントの使用には踏み込みたくないのです。これはオープンソースのプロジェクトではないので、"プラグイン"があることを期待していません。ポイントは、メインアプリケーションのコードを簡素化し、新しいコマンドモジュールが追加されるたびにそれを修正する必要性をなくすことです。

解決するには?

2.7/3.1より古いPythonでは、かなりの確率でそのようになります。

新しいバージョンでは importlib.import_module に対して Python 2 Python 3 .

を使用することができます。 exec を使用することもできます。

または __import__ というようにすると、モジュールの一覧をインポートすることができます。

>>> moduleNames = ['sys', 'os', 're', 'unittest'] 
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)

より抜粋 Pythonに飛び込む .