DEBUG-相对模块导入问题

问题:

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的父级目录,成功解决问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值