Python 尝试从展开的命名空间导入模块时发生ModuleNotFoundError

Python 尝试从展开的命名空间导入模块时发生ModuleNotFoundError,python,python-3.x,python-import,Python,Python 3.x,Python Import,假设我的项目结构如下: proj ├── __init__.py └── core ├── __init__.py └── a ├── __init__.py └── foo.py 其中,只有以下非空文件: # proj/__init__.py from . core import a 及 及 我的想法是将模块a从core中取出,并将其暴露在包的顶层。但是,以下操作失败: >>> from proj.a

假设我的项目结构如下:

proj
   ├── __init__.py
   └── core
      ├── __init__.py
      └── a
         ├── __init__.py
         └── foo.py
其中,只有以下非空文件:

# proj/__init__.py
from . core import a

我的想法是将模块
a
core
中取出,并将其暴露在包的顶层。但是,以下操作失败:

>>> from proj.a import Bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'proj.a'
两个问题:

  • python文档中是否有部分解释了为什么导入/模块系统不允许出现失败的情况?我找不到一个清楚的解释

  • 是否有一种变通方法,使您可以从
    proj.a
    导入,就好像它是
    proj.core.a


  • 首先,让我们排除一个简单的问题:
    import proj.a.Bar as Bar
    无法工作,因为
    Bar
    是一个类,而不是一个模块<出于同样的原因,代码>将项目核心a.Bar导入为Bar也不起作用

    现在用于从
    项目a
    导入。您使用
    \uuu init\uuuuuuuuuuuuuupy
    文件描述的“提升”过程只创建了一个别名-在
    proj.\uuuuu dict\uuuuuuu
    中添加的条目“a”现在绑定到一个模块对象,但其本身并不使模块
    proj.core.a
    成为
    proj
    的直接子模块

    名称“a”只是绑定在两个不同的名称空间中:在
    proj.\uuu dict\uu
    proj.core.\uu dict\uu
    中。来自项目的导入语句
    。导入条
    的处理方式仍与通常相同,尝试查找具有完全限定名
    proj.a
    的模块。Python将从和中选择import machinery(它将使用
    PathFinder
    FileFinder
    ),然后搜索类似于
    proj/a
    的dir/subdir,但没有找到

  • python文档中是否有部分解释了为什么导入/模块系统不允许出现失败的情况?我找不到一个清楚的解释
  • 我能找到的最好的例子是在导入系统文档的这一部分,其中提到Python需要导入模块的完全限定名。失败的案例没有使用,它使用了其他名称

  • 是否有一种变通方法,使您可以从
    proj.a
    导入,就好像它是
    proj.core.a
  • 对。在Python尝试导入模块之前,它首先检查该键是否已缓存在
    sys.modules
    dict中。尝试以下解决方法:

    # proj/__init__.py
    from . core import a
    
    import sys
    sys.modules[f"{__name__}.a"] = a
    
    现在,从项目导入
    。导入条
    可以成功,即使尚未导入
    proj


    您正在劫持importlib,因此Python会主动启用此技巧。甚至还有,因为stdlibxml和etree也依赖于这种行为。虽然源代码注释称之为“疯狂”,但请谨慎使用

    首先,让我们省去一个简单的问题:
    import proj.a.Bar as Bar
    无法工作,因为
    Bar
    是一个类,而不是一个模块<出于同样的原因,代码>将项目核心a.Bar导入为Bar也不起作用

    现在用于从
    项目a
    导入。您使用
    \uuu init\uuuuuuuuuuuuuupy
    文件描述的“提升”过程只创建了一个别名-在
    proj.\uuuuu dict\uuuuuuu
    中添加的条目“a”现在绑定到一个模块对象,但其本身并不使模块
    proj.core.a
    成为
    proj
    的直接子模块

    名称“a”只是绑定在两个不同的名称空间中:在
    proj.\uuu dict\uu
    proj.core.\uu dict\uu
    中。来自项目的导入语句
    。导入条
    的处理方式仍与通常相同,尝试查找具有完全限定名
    proj.a
    的模块。Python将从和中选择import machinery(它将使用
    PathFinder
    FileFinder
    ),然后搜索类似于
    proj/a
    的dir/subdir,但没有找到

  • python文档中是否有部分解释了为什么导入/模块系统不允许出现失败的情况?我找不到一个清楚的解释
  • 我能找到的最好的例子是在导入系统文档的这一部分,其中提到Python需要导入模块的完全限定名。失败的案例没有使用,它使用了其他名称

  • 是否有一种变通方法,使您可以从
    proj.a
    导入,就好像它是
    proj.core.a
  • 对。在Python尝试导入模块之前,它首先检查该键是否已缓存在
    sys.modules
    dict中。尝试以下解决方法:

    # proj/__init__.py
    from . core import a
    
    import sys
    sys.modules[f"{__name__}.a"] = a
    
    现在,从项目导入
    。导入条
    可以成功,即使尚未导入
    proj

    您正在劫持importlib,因此Python会主动启用此技巧。甚至还有,因为stdlibxml和etree也依赖于这种行为。虽然源代码注释称之为“疯狂”,但请谨慎使用

    >>> import proj.a.Bar as Bar
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ModuleNotFoundError: No module named 'proj.a'
    
    >>> from proj.core.a import Bar
    
    # proj/__init__.py
    from . core import a
    
    import sys
    sys.modules[f"{__name__}.a"] = a