我有以下代码来动态加载一个模块:
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
sys.path
。 - Martijn Pieters