如何解决 Python 3.6 中的这个导入错误?

How to resolve this import error in Python 3.6?

我有一个very simple namespace package(下面包含的内容,以及目录布局)。如果我尝试导入 namespace_repro.module,我收到以下错误:AttributeError: module 'namespace_repro' has no attribute 'module'。据我所知,我的包裹有一个有效的布局并且导入应该有效。有趣的是,该错误仅出现在 Python 3.6.8 中,而在 Python 3.7.

中导入成功

如何重现问题?

我有一个名为 import-error-repro 的目录,其中有一个 setup.py(见下文),然后是一个嵌套目录路径 src/namespace_repro/module,包含三个文件 __init__.pyx.pyy.py。他们的内容:

setup.py

from setuptools import find_namespace_packages, setup

setup(
    name='namespace-repro',
    version='0.1.0',
    python_requires='>=3.6',
    packages=find_namespace_packages('src'),
    package_dir={'': 'src'},
    zip_safe=False,
)

src/namespace_repro/module/__init__.py:

from namespace_repro.module.x import x

src/namespace_repro/module/x.py:

import namespace_repro.module.y as y

x = y.y

最后 src/namespace_repro/module/y.py:

y = True

我通过 conda create -n namespace6 python=3.6 ipython 创建了一个全新的 Python 3.6 conda 环境,然后我激活了它并安装了 pip install -e ./import-error-repro 的包(注意 -e 没有重要的是,没有它,问题是可以重现的)。之后,我在 ipython 中尝试了 import namespace_repro.module (尽管在官方 python 解释器中也发生了同样的情况)。结果是

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-bcae5a697dad> in <module>
----> 1 import namespace_repro.module

~/namespace-repro/src/namespace_repro/module/__init__.py in <module>
----> 1 from namespace_repro.module.x import x

~/namespace-repro/src/namespace_repro/module/x.py in <module>
----> 1 import namespace_repro.module.y as y
      2 
      3 x = y.y

AttributeError: module 'namespace_repro' has no attribute 'module'
---------------------------------------------------------------------------

奇怪的是,导入系统发现namespace_repro.module两次,第三次都失败了!

其他一些有趣的行为:

In [1]: import namespace_repro.module.y as y  # This doesn't work.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-4035347ea59b> in <module>
----> 1 import namespace_repro.module.y as y

AttributeError: module 'namespace_repro' has no attribute 'module'

In [2]: import namespace_repro.module.y  # But this one does! Why?

In [3]: dir(namespace_repro.module.y) # The error returns when we actually want to use the module.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-d89bcfd9e509> in <module>
----> 1 dir(namespace_repro.module.y)

AttributeError: module 'namespace_repro' has no attribute 'module'

In [4]: from namespace_repro.module.y import y  # This works fine!

In [5]: y
Out[5]: True

目录布局

. import-error-repro
+-- setup.py
+-- src
|   +-- namespace_repro
|   |   +-- module
|   |   |   +-- __init__.py
|   |   |   +-- x.py
|   |   |   +-- y.py

这是 CPython 错误 30024,不出所料,它已在 3.7 中修复。请注意,具有相对(循环)导入的更惯用的形式自 3.5 以来一直有效。