我能想到的最简单的解决方案是sys.path
在执行导入的函数中暂时修改:
from contextlib import contextmanager @contextmanager def 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_path def 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_code(module.__name__),module.__dict__)
被调用.这里spec.loader.get_code(module.__name__)
只是lib.py中包含的代码.
因此import
,只需通过exec语句的第二个参数注入一个或多个全局变量,就可以找到一种方法使语句的行为不同.但是,"无论你做什么使导入机器看起来都在该文件的文件夹中,它都必须在初始导入的持续时间之后停留,因为当你调用它们时,该文件中的函数可能会执行进一步的导入",如@所述. user2357112在问题评论中.
不幸的是,改变import
语句行为的唯一方法似乎是改变sys.path
或在包中__path__
.module.__dict__
已经包含__path__
使似乎不工作,这叶子sys.path
(或者试图找出为什么执行不会代码当作一个包,即使它有__path__
和__package__
... -但我不知道从哪里开始-也许它有与没有__init__.py
文件有关的事情).
此外,这个问题似乎并不具体,importlib
而是兄弟进口的一般问题.
编辑2:如果您不希望模块sys.modules
以下结尾应该工作(请注意,sys.modules
导入过程中添加的任何模块都将被删除):
from contextlib import contextmanager @contextmanager def 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
将PYTHONPATH
应用程序所在的路径添加到环境变量中
增加模块文件的默认搜索路径.格式与shell的PATH相同:一个或多个目录路径名由os.pathsep分隔(例如Unix上的冒号或Windows上的分号).默认忽略不存在的目录.
在bash上它是这样的:
export PYTHONPATH="./folder/:${PYTHONPATH}"
或直接运行:
PYTHONPATH="./folder/:${PYTHONPATH}" python directory/app.py