前言
??本篇博客主要分析在命令行执行Python 脚本时提示ModuleNotFoundError: No module named 'xxxxxxx' 产生的原因,并给出了解决方法。
1. 问题描述
??在项目开发过程中遇到了一个问题:项目代码在PyCharm 中能够正常运行,但是通过命令行终端运行Python 脚本时出现ModuleNotFoundError: No module named 'xxxxxxx' ,其中'xxxxxxx' 不是通过pip 安装的,而是自定义的package 。为了更好更直观地分析问题,我模拟了问题发生的工程代码文件目录:
.
├── package1
│ ├── __init__.py
│ ├── package1_1
│ │ ├── __init__.py
│ │ └── pkg1_1.py
│ ├── package1_2
│ │ ├── __init__.py
│ │ └── pkg1_2.py
│ └── pkg1.py
└── package2
├── __init__.py
├── package2_1
│ ├── __init__.py
│ ├── package2_1_1
│ │ ├── __init__.py
│ │ ├── main.py
│ │ └── pkg_2_1_1.py
│ └── pkg2_1.py
└── pkg2.py
import argparse
from package1 import pkg1
from package2 import pkg2
from package1.package1_2 import pkg1_2
from package2.package2_1 import pkg2_1
import pkg_2_1_1
parser = argparse.ArgumentParser()
parser.add_argument('--execmd', type=str, required=True, help='execute file yes or no')
parser.add_argument('--nums', type=int, default=1, help='execute nums')
args = parser.parse_args()
def main():
pkg1.print_info()
pkg2.print_info()
pkg1_2.print_info()
pkg2_1.print_info()
pkg_2_1_1.print_info()
if __name__ == '__main__':
if args.execmd == 'yes':
for i in range(args.nums):
print('{:*^35}'.format(i))
main()
print('{:*^35}'.format(i))
else:
print('nothing to do.')
??代码不难理解,下面在PyCharm 中配置一下输入的参数并运行该代码:
??下面在命令行终端运行main.py 文件,代码运行命令为:
python main.py --execmd=yes --nums=1
Traceback (most recent call last):
File "main.py", line 2, in <module>
from package1 import pkg1
ModuleNotFoundError: No module named 'package1'
??执行main.py 文件报错了!!!!
2. 问题原因
??根据代码的错误信息可以了解到,代码在执行的过程中,Python 解释器没有找到package1 ,package1 是自定义的一个包,根据上面的文件目录的树结构可以看到package1 这个包确实是存在的,但是Python 解释器却没有发现,这么明显的一个包竟然看不见?????
??那就得想一想为啥Python 解释器找不到这个包,想着想着就想到了。。。。。。
??咳咳,不知道有没有用过百度的AI Studio ,在新建项目的时候,平台会默认给我们创建一个Jupyter 文件:
??在文件的最下面有几条命令:
!mkdir /home/aistudio/external-libraries
!pip install beautifulsoup4 -t /home/aistudio/external-libraries
import sys
sys.path.append('/home/aistudio/external-libraries')
??每次运行项目的时候不必每次都要安装项目所需的包,可以在pip 安装包的时候指定安装的文件路径,使用的时候再通过sys.path 引入相关的包。 ??此时此刻,问题应该已经有了答案,加入sys.path 之后Python 解释器就会去这个路径下找项目所需的package 。下面就分析一下这个sys.path 是干甚的(PS:不分析也知道,跟路径有关)。
3. sys.path
??sys 是Python 内置的一个模块,是一个与系统相关的参数和函数,具体可参见官方文档。而sys.path 是一个一个由字符串组成的列表,用于指定模块的搜索路径,其中path[0] 目录含有调用 Python 解释器的脚本,具体可参阅官方文档。
??现在知道了为什么在命令行终端执行Python 文件有时候会出现ModuleNotFoundError: No module named 'xxxxxxx' ,但还有一个问题,为什么在PyCharm 中可以执行呢? ??打印一下默认的搜索路径就知道了,也就是打印一下sys.path :
['/home/liyanpeng/Documents/coder/pywork/myproject/package2/package2_1/package2_1_1',
'/home/liyanpeng/Documents/coder/pywork/myproject',
'/usr/share/pycharm-2021.2/plugins/python/helpers/pycharm_display',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python36.zip',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python3.6',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python3.6/lib-dynload',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python3.6/site-packages',
'/usr/share/pycharm-2021.2/plugins/python/helpers/pycharm_matplotlib_backend']
['/home/liyanpeng/Documents/coder/pywork/myproject/package2/package2_1/package2_1_1',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python36.zip',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python3.6',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python3.6/lib-dynload',
'/home/liyanpeng/anaconda3/envs/pytorch/lib/python3.6/site-packages']
??可以看出,PyCharm 中的搜索路径和命令行终端的搜索路径还是略有区别的,列表中的第一个文件目录表示的是脚本文件,也就是main.py 所在的目录,对应的第二个元素就不一样了,命令行终端的搜索路径列表中没有'/home/liyanpeng/Documents/coder/pywork/myproject' ,相必已经猜到了,没错,这个目录就是package1 所在的目录,也就是本项目的根目录:
4. 解决方法
??在main.py 中加入该目录,如何加???,加在哪???
import sys
sys.path.append('/home/liyanpeng/Documents/coder/pywork/myproject')
import argparse
from package1 import pkg1
...
parser = argparse.ArgumentParser()
parser.add_argument('--execmd', type=str, required=True, help='execute file yes or no')
parser.add_argument('--nums', type=int, default=1, help='execute nums')
args = parser.parse_args()
...
??再次执行命令:python main.py --execmd=yes --nums=1 ,即可运行成功:
结束语
??一般提示ModuleNotFoundError: No module named 'xxxxxxx' 得到时候就要考虑两个问题,如何'xxxxxxx' 是第三方的安装包,那通过pip install xxxxxxx ,即可解决;如果是自定义的包,那么就要考虑是路径的问题,尤其是在命令行终端的时候,根据报错的具体文件信息,在相应的文件里面(建议在最顶部)通过sys.path 加入项目的根目录。可能还有小伙伴遇到过,在PyCharm 中执行的时候也会出现ModuleNotFoundError: No module named 'xxxxxxx' ,而且'xxxxxxx' 也是自定义的包,此时可以将项目路径设置为根目录即可解决,具体操作为:在项目的根目录上右键 --> Mark Directory as --> Sources Root 。
|