Python:尝试从导入的包中导入模块时出现“ModuleNotFoundError”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/54598292/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 20:29:19  来源:igfitidea点击:

Python: 'ModuleNotFoundError' when trying to import module from imported package

pythonpython-3.xpython-import

提问by strangeloop

I'm using Python 3.7.1 on macOS Mojave Version 10.14.1

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

This is my directory structure:

这是我的目录结构:

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

man1.pycontains the following importstatement, which I do not want to change:

man1.py包含以下导入语句,我不想更改

from Soft.SoftWork.manModules import *

man1test.pycontains the following importstatements:

man1test.py包含以下导入语句:

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

I need the second importin man1test.pybecause man1test.pyneeds access to a function in man1.py.

我需要第二次导入man1test.py因为man1test.py需要访问man1.py.

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

我的第一个导入(背后的理由)是促进上述进口的声明man1.py

Contrary to my expectation, however, the importstatement in man1.pygives rise to:

然而,与我的预期相反,导入语句man1.py导致:

ModuleNotFoundError: No module named 'Soft'

when I run

当我跑

python3 -m man.MansTest.Unittests.man1test

from a directory above man/.

man/上面的目录。

Is there any way to resolve this error without changing the importstatement in man1.pyandwithout adding anything to sys.path?

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

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

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

回答by Gino Mempin

There are a couple of confusingrequirements with your setup but I'll try to give you what you want.

您的设置有一些令人困惑的要求,但我会尽力为您提供您想要的。

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

第一,如果你希望能够访问man1.pyman1test.pymanModules.pyman1.py,您需要正确设置你的文件,包和模块

Packages are a way of structuring Python's module namespace by using “dotted module names”. For example, the module name A.Bdesignates a submodule named Bin a package named A.

...

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

The __init__.pyfiles 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.

包是一种通过使用“带点的模块名称”来构建 Python 模块命名空间的方法。例如,模块名称A.B指定在名为B的包中命名的子模块A

...

导入包时,Python 在目录中搜索 sys.path包子目录。

__init__.py需要这些文件才能使 Python 将目录视为包含包;这样做是为了防止具有通用名称的目录(例如 )string无意中隐藏稍后出现在模块搜索路径上的有效模块。

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

SECOND, for the "ModuleNotFoundError: No module named 'Soft'" error caused by from ...Mans import man1in man1test.py, the documented solution to that is to add man1.pyto sys.pathsince Mansis outside the MansTestpackage. See The Module Search Pathfrom the Python documentation. But if you don't want to modify sys.pathdirectly, you can also modify PYTHONPATH:

SECOND,对于“ModuleNotFoundError: No module named 'Soft'引起”错误from ...Mans import man1man1test.py,所记录的解决方案是添加man1.pysys.path是外MansTest包。请参阅Python 文档中的模块搜索路径。但是如果不想sys.path直接修改,也可以修改PYTHONPATH

sys.pathis initialized from these locations:

  • 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.

sys.path从这些位置初始化:

  • 包含输入脚本的目录(或未指定文件时的当前目录)。
  • PYTHONPATH(目录名称列表,语法与 shell 变量相同PATH)。
  • 依赖于安装的默认值。

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

第三from ...MansTest.SoftLib import Soft你说“是为了促进前面提到的 man1.py 中的导入语句”,这就是导入的工作方式。如果要导入Soft.SoftLibman1.py,你必须设置man1.py找到Soft.SoftLib并直接导入它。

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

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

man1.py:

人1.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"

Terminal output:

终端输出:

$ 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 


As a suggestion, maybe re-think the purpose of those SoftLibfiles. Is it some sort of "bridge" between man1.pyand 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).

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