使用 "current-directory" 导入导入模块
Importing module with "current-directory" imports
我有以下代码来动态加载模块:
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, "."]
哦,是的,理由是我也想支持导入不正确的模块 packages/modules,但只是一些可以在解释器中工作的脚本。
可重现代码:
~/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
你在这里使用动态导入并不重要;同样的问题适用于任何假设当前目录在路径上的代码。这些脚本负责确保当前目录位于它们自己的路径上。
而不是使用 '.'
(当前工作目录),而是使用 __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.path
来重试您的动态导入,当您有一个 ImportError
(也许 detecting it was a transient import that failed ),但这是一个巨大的飞跃,因为您无法区分缺失的依赖项和做出关于 sys.path
.
假设的模块
在我的例子中,有效的是 importlib.import_module('file_basename')
— 没有指定任何包。请参阅下面的试错与成功:
>>> importlib.import_module('.trainer', '.')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 961, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked
ModuleNotFoundError: No module named '.'
>>> importlib.import_module('.trainer', None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/importlib/__init__.py", line 122, in import_module
raise TypeError(msg.format(name))
TypeError: the 'package' argument is required to perform a relative import for '.trainer'
>>> importlib.import_module('.trainer', '')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/importlib/__init__.py", line 122, in import_module
raise TypeError(msg.format(name))
TypeError: the 'package' argument is required to perform a relative import for '.trainer'
>>> importlib.import_module('trainer')
<module 'trainer' from '/home/ubuntu/project1/trainer.py'>
我有以下代码来动态加载模块:
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, "."]
哦,是的,理由是我也想支持导入不正确的模块 packages/modules,但只是一些可以在解释器中工作的脚本。
可重现代码:
~/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
你在这里使用动态导入并不重要;同样的问题适用于任何假设当前目录在路径上的代码。这些脚本负责确保当前目录位于它们自己的路径上。
而不是使用 '.'
(当前工作目录),而是使用 __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.path
来重试您的动态导入,当您有一个 ImportError
(也许 detecting it was a transient import that failed ),但这是一个巨大的飞跃,因为您无法区分缺失的依赖项和做出关于 sys.path
.
在我的例子中,有效的是 importlib.import_module('file_basename')
— 没有指定任何包。请参阅下面的试错与成功:
>>> importlib.import_module('.trainer', '.')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 961, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked
ModuleNotFoundError: No module named '.'
>>> importlib.import_module('.trainer', None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/importlib/__init__.py", line 122, in import_module
raise TypeError(msg.format(name))
TypeError: the 'package' argument is required to perform a relative import for '.trainer'
>>> importlib.import_module('.trainer', '')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/importlib/__init__.py", line 122, in import_module
raise TypeError(msg.format(name))
TypeError: the 'package' argument is required to perform a relative import for '.trainer'
>>> importlib.import_module('trainer')
<module 'trainer' from '/home/ubuntu/project1/trainer.py'>