# Python 路径与包导入核心知识点 ## 一、模块的相对导入:以文件自身位置为基准 ### 核心规则 Python 模块的相对导入(`from . import xxx` / `from .. import xxx`)完全基于**被导入代码文件的物理位置**,与终端运行目录无关。 - `.` 代表当前代码文件所在的目录(包); - `..` 代表当前代码文件所在目录的上级目录(父包)。 ### 示例(项目结构) ``` src/ ├── main.py └── RAG/ # 包(含 __init__.py) ├── rag.py # 待导入模块 └── text_process/ # 同级子包 ``` ### 正确写法 在 `rag.py` 中导入同级的 `text_process` 包: ```python # rag.py from . import text_process # . 代表 RAG 目录(rag.py 所在位置) ``` ### 关键说明 相对导入的核心是「包上下文」,代码文件必须被识别为「包内模块」,而非独立脚本。 --- ## 二、数据集/文件操作:用绝对路径避免路径混淆 ### 核心问题 文件操作的路径(如读取数据集)默认以**终端运行命令的当前目录(CWD)** 为基准,与代码文件位置无关,极易因运行目录不同导致文件找不到。 ### 最优解决方案:统一使用绝对路径 通过 `__file__`(当前代码文件的绝对路径)拼接目标文件路径,彻底摆脱终端运行目录的影响。 ### 封装工具函数(通用模板) ```python import os def get_abs_path(relative_path): """ 获取相对于当前代码文件的绝对路径 :param relative_path: 相对于当前文件的路径(如 "data/dataset.csv") :return: 目标文件的绝对路径 """ # 获取当前代码文件的绝对路径 current_file = os.path.abspath(__file__) # 获取当前代码文件所在目录 current_dir = os.path.dirname(current_file) # 拼接绝对路径 abs_path = os.path.join(current_dir, relative_path) return abs_path # 用法示例(rag.py 中读取 RAG/data/dataset.csv) data_path = get_abs_path("data/dataset.csv") with open(data_path, "r", encoding="utf-8") as f: data = f.read() ``` --- ## 三、Python 运行方式:脚本 vs 模块(-m 参数) ### 两种运行方式的核心区别 | 运行方式 | 本质 | 包上下文 | 相对导入是否生效 | |-------------------------|---------------------|----------|------------------| | `python 文件名.py` | 运行独立脚本 | 无 | ❌ 失效 | | `python -m 包名.模块名` | 以模块方式运行代码 | 有 | ✅ 生效 | ### 问题场景(以 RAG/rag.py 为例) 直接运行脚本会触发相对导入报错: ```bash # 错误示例(终端在 RAG 目录) python rag.py # 报错:ImportError: attempted relative import with no known parent package ``` ### 正确解决方案 1. 切换到包的上级目录(src 目录); 2. 使用 `-m` 参数以模块方式运行: ```bash # 正确示例(终端在 src 目录) python -m RAG.rag ``` ### `-m` 参数的核心作用 `-m`(module)让 Python 先识别包的层级结构,再运行代码,保留「包上下文」,从而支持相对导入语法。 --- ## 核心总结 1. 相对导入:看**代码文件自身位置**,用 `.`/`..` 表示层级; 2. 文件路径:优先用 `__file__` 拼接**绝对路径**,避免依赖终端运行目录; 3. 运行方式:需要相对导入的代码,用 `python -m 包名.模块名` 运行(保留包上下文)。