相对导入不起作用,看起来找不到模块

relative imports doesn't work, looks like can't find the module

我有以下情况,其中 a 是一个目录:

a/
  __init__.py
  first.py
  second.py

__init__.py

print('i\'m starting the directory')
__all__ = ['second', 'first']

first.py

print('hi, i\'m the first')
from . import *

second.py

print('hi, i\'m the second')

所以当我 运行 从交互式提示:

>>> import a.first
i'm starting the directory
hi, i'm the first
hi, i'm the second
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/antox/Scrivania/a/first.py", line 2, in <module>
    from . import *
AttributeError: 'module' object has no attribute 'first'

为什么找不到first.py模块?我的意思是我希望不会出错;在导入 运行 期间,我认为它可以看到 first.py 已经加载,所以没有错误,它只是跳到 [=中列出的下一个=15=].

这似乎是 Python 导入机制中长期存在的错误。问题在于 a 模块在完全加载之前不会添加到其包的全局命名空间中。如果 module 仅部分加载,这会中断 from package import module 语句。不过,您仍然可以使用 import package.module,它长期以来一直得到导入系统的特殊支持。

jonrsharpe commented, the Python developers have been aware of this issue since 2004。由于这个问题只有在包中有涉及模块的循环导入时才会出现,而循环导入通常被认为是糟糕的设计,所以他们没有把修复它放在非常高的优先级。

不过最近有进步! A partial fix 是几个月前为 Python 3.5 添加的,它刚刚发布了第一个 alpha 版本(完整版本计划于 9 月发布)。该修复程序在加载时实际上仍然没有将 module 添加到 package,而是向 from package import module 语句添加了额外的检查,以便它们在之前引发的循环导入情况下仍然可以工作ImportError.

但这并不能解决 from package import * 的问题。通配符导入的代码显然仍然希望 package.__all__ 中的所有名称实际出现在模块本身中。它似乎没有检查 sys.modules 字典来检查仍在加载过程中的模块。

那么,这对您的代码意味着什么?我认为有两个重要的教训:首先,如果可以的话,不要使用循环导入(而是尝试将两个模块中的一些代码提取到第三个实用程序模块中)。其次,不要使用通配符导入(如果 first.py 使用 from . import first, second 你在 Python 3.5 中不会出错)。