话不多说,先上结论!
首先你的import层级应该是规范的,无论在什么子文件中,一律用绝对路径来import,例如下面例子中我们想在 file11.py
文件中 import fold11.file111.py
,那么我们也应该写成 from folder1.folder11 import file111
。这样规范化后再保证python sys搜索包含根目录,就不会出错。包含根目录的方法要么是有必要的子文件中都添加sys.path.append(os.getcwd())
,或者全局把根目录添加到PYTHONPATH
环境变量里。
- 在每个存在问题的代码前加入
import os
import sys
sys.path.append(os.getcwd())
-
也可以在环境变量中添加一个名为
PYTHONPATH
的变量,里面填入你的根目录(这样可以一次性一劳永逸,只不过对每个有需要的工作目录都需要加一下) -
PS也挺重要的: 如果子文件夹存在
__init__.py
,也可能会导致这个问题。这时候需要引用更完整的路径,例如from folder1.folder2 import xx
下面开始谈解释
我们先规范一下我们的多级python文件(模块)的使用标准:
python_multi_level
├── file1.py
├── file2.py
├── folder1
│ ├── file11.py
│ ├── file12.py
│ └── folder11
│ ├── file111.py
│ └── file112.py
├── folder2
│ └── file21.py
所有的执行都是在根目录下运行的,根目录也就是你创建这个项目的最外层文件夹,在我这个例子中就是python_multi_level 这个文件夹。如果用VSCode的话 python_multi_level 也就是你的工作目录。
每个py文件里写入的命令是 print('hello <file name>)
file1.py
调用其他各个文件
(全部都正常调用就好了,很简单)
print('hello file1')
import file2
from folder1 import file11, file12
from folder2 import file21
from folder1.folder11 import file111, file112
file11.py
调用其他各个文件
如果依旧调用它和它下面的子文件 file12, file111 是正常用法,但如果涉及它的父文件 file1,file21 就会报错
正确做法是:其实和上面的import用法一模一样
import os
import sys
sys.path.append(os.getcwd())
print('hello file111')
import file1
import file2
from folder1 import file12
from folder2 import file21
from folder1.folder11 import file112
原理是执行python的时候会根据 sys.path
列表里的路径去寻找包和模块,(通过 print(sys.path)
可以看)。这个列表里默认会有:
- 当前执行脚本所在路径
- 环境变量里PYTHONPATH
- 安装的第三方模块路径
所以这里调用找不到包的错误都是因为编译器在这个列表的路径和子路径下找不到你所需的包, sys.path.append(os.getcwd())
就是手动将当前根目录添加到检索目录里。
另外补充
-
经常看到需要在文件夹下加一个
__init__.py
,在python3中如果这个文件是空的话,是可以不用加的。 -
实验中还发现,多次import只是生效第一次的。