我能想到的最简单的解决方案是
sys.path在执行导入的函数中进行临时修改:
from contextlib import contextmanager@contextmanagerdef add_to_path(p): import sys old_path = sys.path sys.path = sys.path[:] sys.path.insert(0, p) try: yield finally: sys.path = old_pathdef path_import(absolute_path): '''implementation taken from https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly''' with add_to_path(os.path.dirname(absolute_path)): spec = importlib.util.spec_from_file_location(absolute_path, absolute_path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module
除非您同时在另一个线程中进行导入,否则这不会引起任何问题。否则,由于
sys.path已还原到其先前的状态,因此不应有有害的副作用。
编辑:
我意识到我的回答有些不尽人意,但是,深入研究代码后发现,该行
spec.loader.exec_module(module)基本上导致
exec(spec.loader.get_pre(module.__name__),module.__dict__)被调用。这
spec.loader.get_pre(module.__name__)只是lib.py中包含的代码。
因此,对该问题的更好答案将必须找到一种方法
import,只需通过exec语句的第二个参数简单地注入一个或多个全局变量,即可使该语句具有不同的行为。但是,“
@所做的任何使导入机制在该文件的文件夹中显示的操作,都必须持续超出初始导入的持续时间,因为调用该文件时该文件中的函数可能会执行进一步的导入”,如@问题评论中的user2357112。
不幸的是,更改
import语句行为的唯一方法似乎是更改
sys.path或打包
__path__。
module.__dict__已经包含
__path__让似乎并没有工作,这叶子
sys.path(或者试图找出为什么执行不会代码当作一个包,即使它有
__path__和
__package__…
-但我不知道从哪里开始-也许它有与没有
__init__.py文件有关)。
此外,这个问题似乎并不特定于兄弟姐妹进口,
importlib而是一个普遍的问题。
Edit2:
如果您不希望该模块最终出现在
sys.modules下面,则应该可以正常工作(请注意,
sys.modules导入期间添加的所有模块都将被 删除
):
from contextlib import contextmanager@contextmanagerdef add_to_path(p): import sys old_path = sys.path old_modules = sys.modules sys.modules = old_modules.copy() sys.path = sys.path[:] sys.path.insert(0, p) try: yield finally: sys.path = old_path sys.modules = old_modules



