Python:尝试从导入的包中导入模块时出现“ModuleNotFoundError" [英] Python: 'ModuleNotFoundError' when trying to import module from imported package

查看:242
本文介绍了Python:尝试从导入的包中导入模块时出现“ModuleNotFoundError"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 macOS Mojave 版本 10.14.1 上使用 Python 3.7.1

I'm using Python 3.7.1 on macOS Mojave Version 10.14.1

这是我的目录结构:

man/                          
  Mans/                  
          man1.py
  MansTest/
          SoftLib/
                  Soft/
                      SoftWork/
                              manModules.py
          Unittests/
                    man1test.py

man1.py 包含以下 import 语句,我不想更改:

man1.py contains the following import statement, which I do not want to change:

from Soft.SoftWork.manModules import *

man1test.py 包含以下 import 语句:

from ...MansTest.SoftLib import Soft
from ...Mans import man1

我需要 man1test.py 中的第二个 import 因为 man1test.py 需要访问 man1.py<中的函数/代码>.

I need the second import in man1test.py because man1test.py needs access to a function in man1.py.

我在第一次导入 (Soft) 背后的基本原理是在 man1.py 中促进前面提到的 import 语句.

My rationale behind the first import (Soft) was to facilitate the aforementioned import statement in man1.py.

然而,与我的预期相反,man1.py 中的 import 语句产生了:

Contrary to my expectation, however, the import statement in man1.py gives rise to:

ModuleNotFoundError: No module named 'Soft'

当我跑步时

python3 -m man.MansTest.Unittests.man1test

来自 man/ 上面的目录.

有什么方法可以在不更改 man1.py 中的 import 语句的情况下解决此错误,而无需向 sys 中添加任何内容.path?

Is there any way to resolve this error without changing the import statement in man1.py and without adding anything to sys.path?

python3 -m man.ManTest.Unittests.man1test 从问题的原始版本改为 python3 -m man.MansTest.Unittests.man1test>

python3 -m man.ManTest.Unittests.man1test from the original version of the question changed to python3 -m man.MansTest.Unittests.man1test

推荐答案

FIRST,如果您希望能够从 man1test 访问 man1.py.pyman1.py 中的 manModules.py,您需要将文件正确设置为 包和模块.

FIRST, if you want to be able to access man1.py from man1test.py AND manModules.py from man1.py, you need to properly setup your files as packages and modules.

包是一种通过使用来构建 Python 模块命名空间的方法虚线模块名称".例如,模块名称 A.B 指定一个A 包中名为 B 的子模块.

Packages are a way of structuring Python’s module namespace by using "dotted module names". For example, the module name A.B designates a submodule named B in a package named A.

...

在导入包时,Python 会搜索上的目录sys.path 寻找包子目录.

When importing the package, Python searches through the directories on sys.path looking for the package subdirectory.

__init__.py 文件是让 Python 处理包含包的目录;这样做是为了防止具有通用名称的目录,例如 string,无意中从隐藏稍后出现在模块搜索路径上的有效模块.

The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path.

你需要把它设置成这样:

You need to set it up to something like this:

man
|- __init__.py
|- Mans
   |- __init__.py
   |- man1.py
|- MansTest
   |- __init.__.py
   |- SoftLib
      |- Soft
         |- __init__.py
         |- SoftWork
            |- __init__.py
            |- manModules.py
      |- Unittests
         |- __init__.py
         |- man1test.py

第二,对于ModuleNotFoundError: No module named 'Soft'";由 from ...Mans import man1man1test.py 中引起的错误,文档化的解决方案是将 man1.py 添加到 sys.path 因为 MansMansTest 包之外.请参阅 Python 文档中的模块搜索路径.但是如果不想直接修改sys.path,也可以修改PYTHONPATH:

SECOND, for the "ModuleNotFoundError: No module named 'Soft'" error caused by from ...Mans import man1 in man1test.py, the documented solution to that is to add man1.py to sys.path since Mans is outside the MansTest package. See The Module Search Path from the Python documentation. But if you don't want to modify sys.path directly, you can also modify PYTHONPATH:

sys.path 从以下位置初始化:

  • 包含输入脚本的目录(或未指定文件时的当前目录).
  • PYTHONPATH(目录名称列表,语法与 shell 变量 PATH 相同).
  • 依赖于安装的默认值.
  • The directory containing the input script (or the current directory when no file is specified).
  • PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
  • The installation-dependent default.

第三,对于from ...MansTest.SoftLib import Soft,你说的是为了方便前面提到的man1.py中的import语句em>",这就是导入的工作方式.如果你想在man1.py中导入Soft.SoftLib,你必须设置man1.py才能找到Soft.SoftLib 并直接在那里导入.

THIRD, for from ...MansTest.SoftLib import Soft which you said "was to facilitate the aforementioned import statement in man1.py", that's now how imports work. If you want to import Soft.SoftLib in man1.py, you have to setup man1.py to find Soft.SoftLib and import it there directly.

话虽如此,这就是我让它工作的方式.

With that said, here's how I got it to work.

man1.py:

from Soft.SoftWork.manModules import *
# no change to import statement but need to add Soft to PYTHONPATH

def foo():
    print("called foo in man1.py")
    print("foo call module1 from manModules: " + module1())

man1test.py

man1test.py

# no need for "from ...MansTest.SoftLib import Soft" to facilitate importing..
from ...Mans import man1

man1.foo()

manModules.py

manModules.py

def module1():
    return "module1 in manModules"

终端输出:

$ python3 -m man.MansTest.Unittests.man1test
Traceback (most recent call last):
  ...
    from ...Mans import man1
  File "/temp/man/Mans/man1.py", line 2, in <module>
    from Soft.SoftWork.manModules import *
ModuleNotFoundError: No module named 'Soft'

$ PYTHONPATH=$PYTHONPATH:/temp/man/MansTest/SoftLib
$ export PYTHONPATH
$ echo $PYTHONPATH
:/temp/man/MansTest/SoftLib
$ python3 -m man.MansTest.Unittests.man1test
called foo in man1.py
foo called module1 from manModules: module1 in manModules 


建议您重新考虑一下那些 SoftLib 文件的用途.它是某种桥梁"吗?man1.pyman1test.py 之间?您现在的文件设置方式,我认为它不会像您期望的那样工作.此外,被测代码 (man1.py) 从测试文件夹 (MansTest) 下导入内容有点令人困惑.


As a suggestion, maybe re-think the purpose of those SoftLib files. Is it some sort of "bridge" between man1.py and man1test.py? The way your files are setup right now, I don't think it's going to work as you expect it to be. Also, it's a bit confusing for the code-under-test (man1.py) to be importing stuff from under the test folder (MansTest).

这篇关于Python:尝试从导入的包中导入模块时出现“ModuleNotFoundError"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆