【问题标题】:relative imports doesn't work, looks like can't find the module相对导入不起作用,看起来找不到模块
【发布时间】:2015-04-12 02:17:12
【问题描述】:

我有以下情况,其中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 已经加载,因此没有错误,它只是跳到__all__ 中列出的下一个。

【问题讨论】:

  • import first, second 添加到__init__.py,并从first.py 中删除import
  • 是的,我知道还有其他方法可以获得相同的好处,但我想了解在这种情况下发生了什么
  • 发生了什么是__all__ 要求__init__.py 公开first,但它不知道那是什么

标签: python python-3.x


【解决方案1】:

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

正如jonrsharpe 评论的那样,Python 开发人员已经意识到这个问题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 中您将没有错误)。

【讨论】:

  • 对不起,我没有看到你回答。但是,我按照您告诉我的方法进行了尝试,并在 _init_.py 文件中编写了 first=0 代码,一切正常,但我无法理解这个技巧。 __all__ = ['second', 'first']:为什么'second' 没有出现同样的错误?为什么我也不必插入second = 0 语句?需要明确添加什么,尤其是first?机制是什么?
  • 我强烈怀疑将first=0 放入__init__.py 会导致更多的混乱,而不是更少。你最终会得到a.first.first0,而不是你通常期望的对a.first 的引用。导入second 不会遇到同样的问题,因为它能够一直加载而没有任何循环。当它完成加载时,它在a 模块中的条目被放置。另一方面,first 模块仍在加载中,因此在a 中找不到它(尽管如果您直接命名它,而不是使用*,3.5 中的新代码会找到它)。
  • 哦天哪..我很困惑,为什么我有a.first.firstfrom . import * 我的意思是:导入这个目录中的每个模块。现在,first=0_init_.py 文件中定义,所以我希望它附加到 a 目录模块(然后将在first.py) 的导入所以...我不明白 :-(
  • 如果导入成功,你会得到a.first.first(可惜它没有),因为first 模块将自己导入,还有second。这是导致问题的导入的“循环”部分。如果这不是您想要的,您需要更仔细地查看您的代码并决定不同的语句!
  • 好的,知道了。我可以再问一件事吗?为什么在导入过程中会收到AttributeErrorImportError 不是更合适吗?因为如果我打电话给a.nothing,我会遇到同样的错误,而且我不认为我在做这样的事情
猜你喜欢
  • 2020-04-19
  • 2015-04-30
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 2021-10-15
  • 1970-01-01
  • 2022-07-01
  • 2014-10-31
相关资源
最近更新 更多