Python 包引用问题
首先给定一个文件结构,这个结构在大部分的项目中都是非常常见的:
|____ run.py
|____ __init__.py
|____ module_b
| |____ __init__.py
| |____ b.py
| |____ c.py
|____ module_a
| |____ __init__.py
| |____ a.py
其中 module_a
、 module_b
和 module_c
是三个模块,run.py
是一个总的运行脚本。
在 b.py
文件中实现了一个简单的打印函数:
def print_hello():
print('hello')
执行子文件夹的 py 文件
引用同级文件
在 c.py
中引用 b.py
的内容:
from b import print_hello
def print_hello_from_b():
print_hello()
if __name__ == '__main__':
print_hello_from_b()
执行 python module_b/c.py
可以正常运行。
但是这样存在一个问题,就是如果我们的主程序 run.py
去导入这个模块运行:
from module_b import c
c.print_hello_from_b()
会遇到错误 "ModuleNotFoundError: No module named 'b'"
因为在我们当前的文件夹下是没有 b.py
文件的。而为什么 python module_b/c.py
可以正常运行是因为这个方式等价于:
cd module_b
python c.py
进入到 module_b
文件夹去执行 c.py
,因此当前文件夹是包含 b.py
的。
为了避免这个问题,同时也符合谷歌的 Python 规范:"使用模块的全路径名来导入每个模块",我们需要修改 c.py
文件:
from module_b.b import print_hello
def print_hello_from_b():
print_hello()
if __name__ == '__main__':
print_hello_from_b()
此时 run.py
就可以正常运行了。但与此同时,如果直接执行 python module_b/c.py
会报错:“ModuleNotFoundError: No module named 'module_b'”。因为使用了绝对路径,该运行语句再将运行环境定位到模块内部,没有导入的包名了故报错。
解决方法是添加环境变量,在运行子文件夹 py 文件前,将项目环境添加到 PYTHONPATH
:
# 添加当前路径到 Python 环境
export PYTHONPATH=.:$PATH
再执行 python module_b/c.py
即可。
引用其他模块文件
在 a.py 文件中引用该函数:
from module_b import b
def print_hello_from_b():
b.print_hello()
if __name__ == '__main__':
print_hello_from_b()
此时如果执行 python module_a/a.py
会遇见错误:"ModuleNotFoundError: No module named 'module_b'"
可以把执行语句理解为:
cd module_a
python a.py
由于进入 module_a
模块内部了,因此无法找到 module_b
模块。
同样添加项目环境到 PYTHONPATH
后解决:
# 添加当前路径到 Python 环境
export PYTHONPATH=.:$PATH
python module_a/a.py