python导包问题
- 同级目录下的模块导入不进来
- 相对导入
- [既然from a.b import c可以使用,为什么还要相对引入?](#既然from a.b import c可以使用,为什么还要相对引入?)
同级目录下的模块导入不进来
- 在如下文件moduleB项目下直接import moduleA是会报错的,提示找不到该模块,但是可以看到moduleA和moduleB在一个项目文件夹下:

因为imiport模块的路径根据sys.path系统环境目录来导入的,而系统环境目录没有module的地址
之所以pycharm下不报错是因为,pycharm自动将路径添加到了环境目录,可以通过print(sys.path)打印看到有那些路径;可以看到pycharm是默认添加了路径:

脱离 PyCharm,直接用命令行运行,大概率会报错
正规开发里,这么导入不标准、不推荐、非常不规范
- 所以你认为你想到了方法,将路径添加到sys.path下,那么代码就是
sys.path.append(str(Path('./pkg/subpkg1').absolute()))但是这样代码管理会什么复杂混乱,哪天更改了文件名,路径就不对了,或者文件路径改变!!! - 所以我们采用相对导入
相对导入
点表示当前路径,两个点表示上级路径,相对导入必须以from开头,注意上级目录不要再加斜杠或反斜杠
python
from . import modulA
from ..subPkg2 import moduleX
绝对导入(import xxx)才去 sys.path 里找模块;相对导入的逻辑不是sys.path,而是模块下的__package__(这是一个运行时变量,在不同环境中执行值不一样)中去寻找,然而当一个文件作为最开始的文件开始执行的脚本,他的__package__会被设置为none;就像主程序的__name__会被设置为__main__一样。
可以通过print(package )打印当前的package里有什么。
在启动文件下打印会打印none,但是在调用其他包里的打印__package__函数就不是空的
moduleA里的printpackage函数是我自己编写的打印__package__的函数

所以如果你想使用相对导入,可以先创建一个文件,将需要的文件相对导入写到这个文件里,然后再通过主文件绝对导入调用该文件实现
既然from a.b import c可以使用,为什么还要相对引入?
相对导入 = 给 "包内部" 自己人用的,为了【包可移动、不改名、不乱套】。
b.py 用绝对导入:
python
from my_package import a
看上去没问题。
但万一:
包改名了 → 变成 new_package
包挪到更深的目录 → 变成 project.lib.my_package
结果:所有导入全部失效!要改几百行代码!
- 相对导入的无敌优势:包随便挪,永远不坏
b.py 用相对导入:
python
from . import a # 就找我隔壁的 a 文件
不管你:
把包改名
把包挪到任何目录
把包发给别人用
里面的代码一行都不用改!永远正常运行。
这就是相对导入的核心价值。
- 正规项目为什么一定要用相对导入?
因为正规项目都是做成 "可移动的包"。
你写的不是一堆散文件,而是一个独立模块。独立模块必须做到:不依赖外部路径、不依赖项目名、随便移动都不坏。
只有相对导入能做到。
- 最直观的对比
绝对导入(from my_package.a import x)
依赖包名
包一改名字 → 全炸
适合:顶层入口文件、外部调用包
相对导入(from .a import x)
不依赖包名
只看当前目录
随便移动、改名都没事
适合:包内部文件互相导入
- 官方规范就是这么规定的
Python 官方规范:
包内部互相导入 → 必须用相对导入(带点)
外部使用包 → 用绝对导入
终极总结(背会这 2 句)
绝对导入:从外面找里面,依赖路径和包名。
相对导入:自己人找自己人,不依赖路径、随便移动都不坏。
所以:包内部文件互相导入,必须用相对导入!这才是专业 Python 开发的标准。