这也是一个非常经典且容易让人“头大”的知识点别担心这绝不是因为你笨而是因为 Python 的导入机制设计得既灵活又有些“隐晦”初学者甚至老手很容易在相对导入和绝对导入之间晕头转向。结合最新的最佳实践我用最直白的方式帮你梳理清楚。一、核心概念文件、模块、包想象你在整理一个图书馆文件 (.py)一本书任何以.py结尾的文件就是一个模块 (Module)。例如utils.py就是一个模块里面写着一些工具函数。包 (Package)一个书架文件夹一个包含__init__.py文件的文件夹Python 才会把它当作“包”。__init__.py可以是空的它的作用就是告诉 Python“嘿这个文件夹是个包不是普通文件夹”包里可以放很多模块书也可以放子包子书架。 典型的项目结构示例my_project/ # 项目根目录 ├── main.py # 入口脚本通常不在包内 └── my_package/ # 【包】(因为有 __init__.py) ├── __init__.py # 包的身份证 ├── module_a.py # 【模块】 ├── module_b.py # 【模块】 └── sub_package/ # 【子包】 ├── __init__.py └── module_c.py # 【模块】二、import的两种主要姿势1. 绝对导入 (Absolute Import) ——推荐首选就像给书一个“从根目录开始”的完整地址。无论你在哪个文件里只要路径对就能找到。语法import 包名.模块名或from 包名.模块名 import 内容特点清晰、明确不容易出错。场景演示 假设你在my_package/module_a.py中想使用module_b.py里的函数func_b。# 在 module_a.py 中 from my_package.module_b import func_b # 或者 import my_package.module_b my_package.module_b.func_b()注意使用绝对导入时你的项目根目录 (my_project) 必须在 Python 的搜索路径 (sys.path) 中。通常直接运行python main.py(其中 main.py 在项目根目录) 会自动包含根目录。2. 相对导入 (Relative Import) ——包内部专用就像在图书馆里说“去隔壁书架拿那本书”。只能用点 (.) 来表示相对位置。限制只能在包内部的文件中使用不能在最外层的脚本如main.py中直接使用。.(一个点)当前包当前文件夹。..(两个点)上一级包父文件夹。...(三个点)上两级包以此类推。场景演示 还是假设你在my_package/module_a.py中。导入同级的module_bfrom .module_b import func_b # 点代表当前包 (my_package)导入子包里的module_c(假设你在my_package/__init__.py中)from .sub_package.module_c import func_c如果是深层嵌套 假设你在my_package/sub_package/module_c.py想导入my_package/module_a.pyfrom ..module_a import func_a # 两个点代表退回到 my_package三、from ... import ...的详细用法拆解这是最容易混淆的地方我们把它拆成三种常见写法写法 A导入整个模块import my_package.module_a # 使用时必须带前缀 my_package.module_a.my_function()优点命名空间清晰知道函数来自哪里。缺点打字多。写法 B从模块导入特定对象最常用from my_package.module_a import my_function, MyClass # 使用时直接叫名字 my_function() MyClass()优点代码简洁。风险如果不同模块里有同名函数后面的会覆盖前面的。写法 C导入所有内容不推荐❌from my_package.module_a import *后果把module_a里所有不以下划线_开头的名字全倒进当前 namespace。为什么不好你根本不知道当前作用域里多了哪些名字极易造成命名冲突代码可读性极差。除非你非常清楚自己在做什么否则永远别用*。四、避坑指南新手常犯的“边界错误”这里就是你之前觉得“想不明白”的高发区❌ 错误 1在包外使用相对导入如果你在main.py(项目根目录下) 写# main.py from .my_package import module_a # ❌ 报错原因main.py本身不是一个包的一部分它没有“上级包”的概念。相对导入必须在包内部文件之间使用。✅ 修正在main.py中使用绝对导入。from my_package import module_a❌ 错误 2运行方式不对导致ImportError即使代码写对了运行命令不对也会挂。 假设结构如上你在my_package/module_a.py里写了from .module_b import func_b。错误运行cd my_project/my_package python module_a.py # ❌ 报错attempted relative import with no known parent package原因当你直接运行module_a.py时Python 把它当作顶级脚本不知道它属于my_package包所以相对导入失效。正确运行 回到项目根目录使用-m参数以模块方式运行cd my_project python -m my_package.module_a # ✅ 成功原理-m告诉 Python“请把my_package.module_a当作包里的一个模块来加载”这样 Python 就能识别出它的包上下文相对导入也就生效了。❌ 错误 3忘记__init__.py在 Python 3.3 中虽然有了“隐式命名空间包”但为了兼容性和明确性最好还是在每个作为包的文件夹下放一个空的__init__.py。如果没有它某些旧工具或特定导入方式可能会失效。五、总结与最佳实践建议优先使用绝对导入 只要可能尽量写from my_package.module import func。它更清晰重构时更容易移动文件时不用改一堆..。相对导入仅用于包内部紧密耦合的模块 如果你确定几个模块永远会在同一个包里一起移动可以用from .sibling import func。永远不要直接运行包内的文件 如果要测试包内的代码请在项目根目录使用python -m package.module或者在包外写一个main.py来调用。项目结构要规范ProjectRoot/ ├── src/ # 源代码目录进阶做法防止导入混乱 │ └── my_package/ │ ├── __init__.py │ └── ... ├── tests/ # 测试代码 ├── main.py # 入口 └── requirements.txt(注大型项目常把代码放在src目录下这样能强制你使用正确的导入路径避免 accidentally 导入当前目录下的临时文件)一句话心法 把包想象成俄罗斯套娃。绝对导入是告诉别人“去最大的那个娃娃里找第三层的小娃娃”。相对导入是告诉别人“就在我手里这个娃娃的隔壁找”。如果你站在桌子旁main.py你就不能说“在我手里的娃娃隔壁”因为你手里没娃娃。希望这次解释能帮你打通任督二脉如果还有具体的代码片段让你困惑随时发出来我们现场调试。from Qwen