4

モジュールを動的にロードする次のコードがあります。

def load_module(absolute_path):
    import importlib.util
    module_name, _ = os.path.splitext(os.path.split(absolute_path)[-1])
    try:
        py_mod = imp.load_source(module_name, absolute_path)
    except ImportError:
        module_root = os.path.dirname(absolute_path)
        print("Could not directly load module, including dir: {}".format(module_root))
        spec = importlib.util.spec_from_file_location(
            module_name, absolute_path, submodule_search_locations=[module_root, "."])
        py_mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(py_mod)
    return py_mod

同じフォルダーにスクリプトをインポートしようとしている場合を除いて(同じ名前のパッケージの一部ではありません)、非常にうまく機能します。たとえば、スクリプトa.pyは実行していimport bます。エラーが発生しますImportError: No module named 'b'(これは Python 3 で一般的です)。

しかし、私は本当にこれを解決する方法を見つけたいですか? 先頭に追加することで解決されます:

import sys
sys.path.append(".")

「a」をスクリプト化します。

私はそれが解決されることを望んでいましたが:

submodule_search_locations=[module_root, "."]

そうそう、その根拠は、適切なパッケージ/モジュールではなく、インタープリターで機能するいくつかのスクリプトであるモジュールのインポートもサポートしたいということです。

再現可能なコード:

~/example/a.py

import b

~/example/b.py

print("hi")

~/somewhere_else/main.py (a/b とは別の場所)

import sys, os, imp, importlib.util

def load_module(absolute_path) ...

load_module(sys.argv[1])

次に、コマンド ラインで実行します。

cd ~/somewhere_else
python3.5 main.py /home/me/example/a.py

その結果、ImportError: No module named 'b'

次のコードはそれを解決しますが、もちろんsys.path、すべてのスクリプトに手動で入れることはできません。

~/example/a.py (2)

import sys
sys.path.append(".")
import b

私がまだ考えていなかった解決策を他の人が持っていることを本当に願っています。

付録

def load_module(absolute_path):
    import importlib.util
    module_name, _ = os.path.splitext(os.path.split(absolute_path)[-1])
    try:
        py_mod = imp.load_source(module_name, absolute_path)
    except ImportError as e:
        if "No module named" not in e.msg:
            raise e

        missing_module = e.name
        module_root = os.path.dirname(absolute_path)

        if missing_module + ".py" not in os.listdir(module_root):
            msg = "Could not find '{}' in '{}'"
            raise ImportError(msg.format(missing_module, module_root))

        print("Could not directly load module, including dir: {}".format(module_root))
        sys.path.append(module_root)
        spec = importlib.util.spec_from_file_location(module_name, absolute_path)
        py_mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(py_mod)
    return py_mod
4

2 に答える 2

5

ここで動的インポートを使用していることは問題ではありません。同じ問題が、現在のディレクトリがパス上にあると仮定するコードにも当てはまります。現在のディレクトリがパス自体にあることを確認するのは、これらのスクリプトの責任です。

'.'(現在の作業ディレクトリ) を使用するのではなく、グローバル__file__を使用してディレクトリをパスに追加します。

import os.path
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)

がある場合に を追加して動的インポートを再試行できます(おそらく、失敗した一時的なインポートであることが検出されます) が、欠落している依存関係と.os.path.dirname(absolute_path)sys.pathImportErrorsys.path

于 2016-08-06T12:36:01.443 に答える