【问题标题】:Python: 'ModuleNotFoundError' when trying to import module from imported packagePython:尝试从导入的包中导入模块时出现“ModuleNotFoundError”
【发布时间】:2019-07-03 01:01:37
【问题描述】:

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

这是我的目录结构:

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

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

from Soft.SoftWork.manModules import *

man1test.py 包含以下 import 语句:

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

我需要man1test.py 中的第二个import,因为man1test.py 需要访问man1.py 中的函数。

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

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

ModuleNotFoundError: No module named 'Soft'

当我跑步时

python3 -m man.MansTest.Unittests.man1test

从上面的目录man/

有没有什么方法可以解决这个错误而不改变man1.py中的import语句而不向sys.path添加任何东西?

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

【问题讨论】:

  • 您可以破解 __path__ 的导入模块。不是sys.path,但你可以吗?

标签: python python-3.x python-import


【解决方案1】:

FIRST,如果您希望能够从 man1test.pymanModules.py 访问 man1.py em> 来自 man1.py,您需要将文件正确设置为 packages and modules

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

...

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

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

你需要把它设置成这样:

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,对于 man1test.pyfrom ...Mans import man1 引起的“ModuleNotFoundError: No module named 'Soft'”错误,文档化的解决方案是添加 man1. pysys.path,因为 MansMansTest 包之外。请参阅 Python 文档中的 The Module Search Path。但是如果不想直接修改sys.path,也可以修改PYTHONPATH

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

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

第三,对于您所说的 from ...MansTest.SoftLib import Soft是为了促进 man1.py 中的上述导入语句”,这就是导入的工作方式。如果你想在man1.py中导入Soft.SoftLib,你必须设置man1.py找到Soft.SoftLib 并直接导入那里。

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

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

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

man1.foo()

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) 下导入内容有点令人困惑。

【讨论】:

  • 感谢您的详尽回答。我目前正忙于另一个项目,没有时间实施您的解决方案,这就是为什么我还没有将答案标记为“已接受”的原因。我确实支持它,但它不会显示,因为我是新来的,并且声望不到 15。无论如何,关于你如何让它工作,是否有修改 PYTHONPATH 的替代方法?我想在不修改任何“路径”的情况下解决此问题,以便代码可以按原样传输并供其他人使用,而无需对其“路径”进行任何修改。再次感谢!
  • @strangeloop 嗯..我认为没有其他方法。如果你阅读了the Module Search Path 的 Python 文档,解释器就是这样找到你的 import 文件的。如果你想让代码可移植并且避免其他人做额外的步骤,你可以在 man1test.py 内部修改sys.pathbefore 你导入 man1.py 。路径修改只会在您的程序运行之前生效,它不会影响您用户的环境。用户只需要确保正确复制文件夹即可。
【解决方案2】:

我也遇到过类似的问题,虽然不一样。

我的文件夹和文件的结构(GUI_ML 是主文件夹):

GUI_ML
\ Views \ login.py
\ Views \ __ init __.py
\ Controllers \ Control_login.py
\ Controllers \ __ init __.py

我需要从 login.py 中导入 Control_login.py。以下代码解决了我的问题:

import sys
import os
myDir = os.getcwd()
sys.path.append(myDir)

from pathlib import Path
path = Path(myDir)
a=str(path.parent.absolute())

sys.path.append(a)

from Controllers.Control_login import Control_login

【讨论】:

    【解决方案3】:

    对我来说,当我创建一个文件并将其保存为 python 文件时,我在导入过程中遇到了这个错误。 我必须创建一个类型为 ".py" 的文件名,例如 filename.py,然后将其保存为 python 文件。 尝试导入文件的帖子对我有用。

    【讨论】:

      【解决方案4】:

      modulenotfounderror 由于解释器找不到指定的包而导致。因此,请检查指定的包是否安装了正确的路径到脚本中指定的包。

      还可以使用 sys.path.append 指定所需的包路径。

      更多相关查询可以查看modulenotfounderror reasons with respected answer

      import sys
      sys.path.append('path_to_dir') 
      

      【讨论】:

        【解决方案5】:

        某些包名和模块名可能相同。此冲突也会以此错误响应。

        【讨论】:

          猜你喜欢
          • 2021-07-12
          • 2021-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-21
          • 2021-07-29
          • 2021-07-07
          • 1970-01-01
          相关资源
          最近更新 更多