问题:
nnunetv2/ ├── configuration.py └── experiment_planning/ └── plan_and_preprocess_entrypoints.py └── plan_and_preprocess_api.py ├── __init__.py
文件目录如上
其中plan_and_preprocess_entrypoints.py是我运行的脚本,
其中部分代码如下
from nnunetv2.experiment_planning.plan_and_preprocess_api import extract_fingerprints, plan_experiments, preprocess
该脚本使用from nnunetv2.configuration import default_num_processes,但是显示ModuleNotFoundError: No module named 'nnunetv2'
问题解决:
from nnunetv2.configuration import default_num_processes
是 绝对导入
使用模块的完整路径,例如 from nnunetv2.configuration import default_num_processes
,表示从根目录下的 nnunetv2/configuration.py
文件导入 default_num_processes
。
解决方法1:将工作目录切换到nnunetv2父级目录(不是父级的父级)并确保nnunetv2目录下存在init.py文件
根目录(即你执行脚本时所在的目录),
根目录需要满足:在项目的根目录中运行脚本,并且该目录中包含了 nnunetv2
目录
你在项目的根目录运行脚本,而不是进入到 nnunetv2
目录内运行。
仍有可能失效,
ModuleNotFoundError: No module named 'nnunetv2'
错误,这通常是因为 Python解释器 在该目录下无法找到 nnunetv2
包。尽管你在绝对导入时指定了 nnunetv2
,但如果 project_root
(父级)目录没有被正确添加到 Python 的模块搜索路径 (sys.path
),那么 Python 仍然无法找到 nnunetv2
。
核心问题:python解释器需要在目录中找到 nnunetv2
包
解决方法2:通过修改 sys.path
import sys import os sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
假设你的项目结构如下:
bash 复制代码 /parent_dir/ ├── project_root/ │ ├── nnunetv2/ │ │ ├── configuration.py │ │ └── ... │ ├── script.py │ └── ... └── ...os.path.dirname(file):
__file__
是当前 Python 脚本的文件路径(即脚本文件本身的完整路径)。
os.path.dirname(__file__)
获取当前文件所在的目录。换句话说,它返回的是你当前脚本的目录路径。如果你的脚本在
/parent_dir/project_root/script.py
,那么os.path.dirname(__file__)
会返回/parent_dir/project_root
。os.path.join(os.path.dirname(file), '..'):
os.path.join()
用于拼接路径。在这里,它将当前脚本所在的目录(os.path.dirname(__file__)
)与'..'
连接起来。
'..'
表示父级目录,因此这个操作的结果就是获取 当前脚本的父级目录。例如,如果当前脚本在
/parent_dir/project_root/script.py
,那么os.path.join('/parent_dir/project_root', '..')
会返回/parent_dir
。os.path.abspath(...):
os.path.abspath()
将相对路径转换为绝对路径。如果给定的路径已经是绝对路径,它就会直接返回该路径。通过
os.path.abspath(os.path.join(...))
,最终得到的是 父级目录的绝对路径。例如,在
/parent_dir/project_root
下运行script.py
,经过这步,路径会变成/parent_dir
。sys.path.append(...):
最后,
sys.path.append()
将通过上述方法得到的父级目录路径添加到sys.path
中。这会告诉 Python 查找模块时,也要在这个父级目录下进行查找。
sys.path
中的路径会按顺序进行搜索,确保 Python 能够找到父级目录中的模块。
经过测试,没有用
解决方法3:将工作目录cd至nnunetv2父级目录再如下
export PYTHONPATH=$(pwd):$PYTHONPATH
使用如上语句,成功解决
修改 PYTHONPATH
环境变量将当前工作目录添加到 PYTHONPATH 中,供 Python 解释器在搜索模块时使用。
PYTHONPATH
是一个环境变量,作用是告诉 Python 解释器在哪里查找模块。Python 会按照PYTHONPATH
中列出的目录顺序查找模块,直到找到匹配的模块为止。如果没有找到,它会继续查找默认的系统路径(如site-packages
)或者从当前工作目录中查找。
更重要的是,对于该项目的所有绝对导入,通过这个方法均可以解决,不必手动修改sys.path
PYTHONPATH 环境变量与 sys.path 的区别
PYTHONPATH:这是一个环境变量,影响的是 Python 启动时如何配置模块查找路径。它是在 Python 启动之前设置的,决定了 Python 在查找模块时的初始路径。
sys.path:这是一个 Python 列表,它存储了 Python 解释器当前的模块查找路径。当你运行 Python 脚本时,
sys.path
是 Python 解释器用来查找模块的路径列表。你可以在脚本中动态修改它,例如通过sys.path.append(...)
来手动添加新的模块路径。在 Python 启动时,
PYTHONPATH
环境变量的值会被加载到sys.path
中。可以认为,sys.path
是 Python 在运行过程中模块查找路径的最终状态,而PYTHONPATH
则是启动时用于配置路径的“初始状态”。
二者的目的是一样的:都用于让 Python 解释器能够找到指定的模块目录(比如 nnunetv2
)
验证 PYTHONPATH
无论你是临时设置还是永久设置,都可以通过打印 sys.path
来验证 PYTHONPATH
是否正确设置:
import sys print(sys.path) 结果 ["', '/home/zhang/project_todo/Uu-Mamba/uumamba', '/home/zhang/project_todo/Uu-Mamba', '/home/zhang/anaconda3/envs/FusionMamba/lib/python38.zip', '/home/zhang/anaconda3/envs/FusionMamba/lib/python3.8',*/home/zhang/anaconda3/envs/FusionMamba/lib/python3.8/lib-dynload',,*/home/zhang/anaconda3/envs/FusionMamba/lib/python3.8/site-packages']
得出结论,需要将父级目录/home/zhang/project_todo/Uu-Mamba/uumamba变为sys.path的第一个才有用
得到方法2的失败原因:
打印 sys.path 的顺序
-
顺序问题: 根据你给出的
sys.path
输出,nnunetv2
目录是出现在最后的,Python 会按顺序在sys.path
中查找模块。如果你的sys.path
中包含的其他路径(例如虚拟环境中的site-packages
)有类似的名称或模块,它可能优先加载检查 nnunetv2 在 sys.path 中的位置: 确保
nnunetv2
目录排在其他路径之后。如果没有问题,你可以尝试将其插入到sys.path
的最前面:
sys.path.insert(0, '/home/zhang/project_todo/UU-Mamba/uumamba')
这样,Python 会优先在这个目录中查找模块。
此处uumamba即nnunetv2的父级目录,成功解决问题