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
Python: 'ModuleNotFoundError' when trying to import module from imported package
提问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.py
contains the following importstatement, which I do not want to change:
man1.py
包含以下导入语句,我不想更改:
from Soft.SoftWork.manModules import *
man1test.py
contains the following importstatements:
man1test.py
包含以下导入语句:
from ...MansTest.SoftLib import Soft
from ...Mans import man1
I need the second importin man1test.py
because man1test.py
needs 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.py
gives 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.py
andwithout adding anything to sys.path?
有什么方法可以解决此错误而无需更改sys.path 中的import语句man1.py
并且不向sys.path添加任何内容?
Edit: python3 -m man.ManTest.Unittests.man1test
from 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.py从man1test.py和manModules.py从man1.py,您需要正确设置你的文件,包和模块。
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 namedB
in a package namedA
....
When importing the package, Python searches through the directories on
sys.path
looking for the package subdirectory.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 asstring
, 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 man1
in man1test.py, the documented solution to that is to add man1.pyto sys.path
since Mansis outside the MansTestpackage. See The Module Search Pathfrom the Python documentation. But if you don't want to modify sys.path
directly, you can also modify PYTHONPATH
:
SECOND,对于“ModuleNotFoundError: No module named 'Soft'
引起”错误from ...Mans import man1
在man1test.py,所记录的解决方案是添加man1.py到sys.path
自芒是外MansTest包。请参阅Python 文档中的模块搜索路径。但是如果不想sys.path
直接修改,也可以修改PYTHONPATH
:
sys.path
is 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 variablePATH
).- The installation-dependent default.
sys.path
从这些位置初始化:
- 包含输入脚本的目录(或未指定文件时的当前目录)。
PYTHONPATH
(目录名称列表,语法与 shell 变量相同PATH
)。- 依赖于安装的默认值。
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.SoftLibin man1.py, you have to setup man1.pyto find Soft.SoftLiband import it there directly.
第三,from ...MansTest.SoftLib import Soft
你说“是为了促进前面提到的 man1.py 中的导入语句”,这就是导入的工作方式。如果要导入Soft.SoftLib在man1.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.py和man1test.py之间的某种“桥梁”吗?您现在的文件设置方式,我认为它不会像您期望的那样工作。此外,被测代码(man1.py)从测试文件夹(MansTest)下导入东西有点令人困惑。