1 背景描述

在新建一个python项目时,项目内文件构造大致如下:

.
├── abc
│   ├── cbd.py
│   └── __init__.py
├── etc
│   └── init.d
│       └── start
├── project_test
│   ├── cmd
│   │   ├── __init__.py
│   │   └── start.py
│   ├── __init__.py
│   ├── main_package
│   │   ├── __init__.py
│   │   └── main.py
│   └── test
│       ├── __init__.py
│       └── model.py
├── requirements.txt
├── setup.cfg
├── setup.py
└── tools

从图中很明显能够看到,每个使用的python文件都在package中,标志是含有__init__.py文件,因此本文讨论的就是非package缺少__init__.py文件的问题。
首先,按照上面的项目格式,直接对项目进行启动(忽略项目虚拟环境),结果如下:

(.venv) [root@vm10-0-1-42 project_test]# /opt/project_test/.venv/bin/python /opt/project_test/.venv/bin/project_test 
Traceback (most recent call last):
  File "/opt/project_test/.venv/bin/project_test", line 11, in <module>
    load_entry_point('project-test==1.0.0', 'console_scripts', 'project_test')()
  File "/opt/project_test/.venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 476, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/opt/project_test/.venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2700, in load_entry_point
    return ep.load()
  File "/opt/project_test/.venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2318, in load
    return self.resolve()
  File "/opt/project_test/.venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2324, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/opt/project_test/.venv/lib/python3.6/site-packages/project_test-1.0.0-py3.6.egg/project_test/cmd/start.py", line 3, in <module>
ModuleNotFoundError: No module named 'abc.cbd'; 'abc' is not a package

结合上面的项目结构,下面给出了这个cbd文件的内容,只有两行:

def play():
    return 111

下面给出了调用这个abc.cbd模块的start文件内容如下:

from project_test.test.model import main_task
  
from abc.cbd import play

def enter_point():
    main_task()

直接执行该start文件报错类似,如下:


```bash
(.venv) [root@vm10-0-1-42 project_test]# python project_test/cmd/start.py 
Traceback (most recent call last):
  File "project_test/cmd/start.py", line 3, in <module>
    from abc.cbd import play
ModuleNotFoundError: No module named 'abc.cbd'; 'abc' is not a package

从项目结构上也能看出,在项目目录下的project_test以及abc都是一级目录,而且都是包。为了排查问题,直接终端导入试试。结果如下:

(.venv) [root@vm10-0-1-42 project_test]# python
Python 3.6.8 (default, Jan 29 2025, 17:12:25) 
[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from project_test.cmd.start import enter_point
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/project_test/project_test/cmd/start.py", line 3, in <module>
    from abc.cbd import play
ModuleNotFoundError: No module named 'abc.cbd'; 'abc' is not a package

可以看出项目里的模块,直接在虚拟环境的终端里也无法导入

2:问题分析

参考了很多文章,有说缺少__init__.py文件的(pass),缺少sys.path.append(‘文件的绝对路径’)(无效)可能不适用我的例子,需要尝试的推荐跳转:https://blog.csdn.net/qq_44886213/article/details/123349273
现在直接贴出我个人找到解决方案:根项目下的一级目录下只能存在一个包目录
根目录设置和pycharm中如下一致
在这里插入图片描述

如下是背景描述中的项目层级解构(忽略虚拟环境)

.
├── abc    <--------项目一级目录下第一个package
│   ├── cbd.py
│   └── __init__.py
├── etc
│   └── init.d
│       └── start
├── project_test   <------项目一级目录下第二个package
│   ├── cmd     <------项目二级目录下第一个package
│   │   ├── __init__.py
│   │   └── start.py
│   ├── __init__.py
│   ├── main_package  <------项目二级目录下第二个package
│   │   ├── __init__.py
│   │   └── main.py
│   └── test  <------项目二级目录下第三个package
│       ├── __init__.py  
│       └── model.py
├── requirements.txt
├── setup.cfg
├── setup.py
└── tools

即,项目里的根目录只能是一个,如果设定了project_test是root_path,那么该目录下的python文件就不能引用外部的package的自定义模块,反之可行的,先再次看看现状:
直接导入project_test内没有导入abc目录下的模块

>>> 
>>> 
>>> from project_test.test import model
>>> 
>>> 

直接导入project_test内有导入abc目录下的模块

>>> from  project_test.cmd.start import enter_point
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/project_test/project_test/cmd/start.py", line 7, in <module>
    from abc.cbd import play
ModuleNotFoundError: No module named 'abc.cbd'; 'abc' is not a package

直接导入abc内的模块

>>> from abc import cbd
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name 'cbd'

接着,在abc目录下的文件导入project_test内的模块
cbd.py修改成如下:

from project_test.test import model
  
def play():
    return 111


if __name__ == '__main__':
    play()

直接python运行该文件不报错

(.venv) [root@vm10-0-1-42 project_test]# 
(.venv) [root@vm10-0-1-42 project_test]# 
(.venv) [root@vm10-0-1-42 project_test]# python abc/cbd.py 
(.venv) [root@vm10-0-1-42 project_test]# 
(.venv) [root@vm10-0-1-42 project_test]# 

反之,直接运行project_test中的start.py文件报错,

(.venv) [root@vm10-0-1-42 project_test]# python project_test/cmd/start.py 
Traceback (most recent call last):
  File "project_test/cmd/start.py", line 4, in <module>
    from abc.cbd import play
ModuleNotFoundError: No module named 'abc.cbd'; 'abc' is not a package

3:解决方案

既然已经确认了问题原因在于多个根目录(package),那么只要变成一个,然后再修改相关的模块新地址即可。
以该项目为例,我打算将abc这个包合并到project_test下,保证项目根路径下只存在唯一一个package目录。
变更后的层级解析如下:

.
├── etc
│   └── init.d
│       └── start
├── project_test
│   ├── abc     <--------挪到project_test目录下了
│   │   ├── cbd.py
│   │   └── __init__.py
│   ├── cmd
│   │   ├── __init__.py
│   │   └── start.py
│   ├── __init__.py
│   ├── main_package
│   │   ├── __init__.py
│   │   └── main.py
│   └── test
│       ├── __init__.py
│       └── model.py
├── requirements.txt
├── setup.cfg
├── setup.py
└── tools

修改cmd.start.py中的导入cbd模块的路径如下
旧:

from abc.cbd import play

新:

from project_test.abc.cbd import play

再虚拟环境下重新编译后,最后项目可以运行了

(.venv) [root@vm10-0-1-42 project_test]# 
(.venv) [root@vm10-0-1-42 project_test]# 
(.venv) [root@vm10-0-1-42 project_test]# /opt/project_test/.venv/bin/python /opt/project_test/.venv/bin/project_test 
hhhh
(.venv) [root@vm10-0-1-42 project_test]# 

直接执行start文件也不会报错

(.venv) [root@vm10-0-1-42 project_test]# python project_test/cmd/start.py 
(.venv) [root@vm10-0-1-42 project_test]# 
(.venv) [root@vm10-0-1-42 project_test]# 

4:其他人解决方案

1:目录引用层级不对,使用绝对路径,从项目路径开始导入,比如

from project_test.project_test.abc.cbd import paly

个人亲测无效,一样报错,

Python 3.6.8 (default, Jan 29 2025, 17:12:25) 
[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from project_test.project_test.abc.cbd import play
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'project_test.project_test'

本文对你无效的话可以试试,原文链接:
https://blog.csdn.net/weixin_41357300/article/details/81190707

2 from 文件夹名 import 文件名 然后在代码中执行引入的方法: 文件名.方法**

个人实测,无效,如下,只导入py文件,感兴趣路过的朋友可以试试,

(.venv) [root@vm10-0-1-42 project_test]# python
Python 3.6.8 (default, Jan 29 2025, 17:12:25) 
[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from project_test.project_test.abc.cbd import play
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'project_test.project_test'
>>> 
>>> 
>>> from  project_test.project_test.abc import cbd
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'project_test.project_test'
>>> from project_test.abc import cbd
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'project_test.abc'
>>> 

参考链接:https://blog.csdn.net/xiangchaoming/article/details/85023291

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐