gpt4 book ai didi

python - 使用绝对导入和__init__.py时是否是循环导入

转载 作者:行者123 更新时间:2023-12-01 03:56:59 27 4
gpt4 key购买 nike

我有以下文件结构,每个文件结构最多有一行代码(如下所示):

a
├── b
│   ├── c.py import a.b.d as d
│   ├── d.py
│   └── __init__.py from a.b.c import *
├── __init__.py
└── main.py import a.b as b

通过运行python -m a.main,我收到以下错误:

Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/tmp/test/a/main.py", line 1, in <module>
import a.b as b
File "a/b/__init__.py", line 1, in <module>
from a.b.c import *
File "a/b/c.py", line 1, in <module>
import a.b.d as d
AttributeError: 'module' object has no attribute 'b'

我不确定这是否是循环导入造成的。如果我将 import a.b.d as d 更改为 from a.b import d,则不再有错误。

最佳答案

AttributeError是由文件c.py中的import语句中的as引起的。

整个过程是这样的:

  1. main.py 创建模块 a,将其添加到 sys.modules 并初始化;
  2. main.py 创建模块a.b,将其添加到sys.modules并开始执行其代码;
  3. b/__init__.py(aa.b 已在 sys.modules 中)创建的模块 a.b.c,将其添加到sys.modules并开始执行其代码;
  4. b/c.py 创建了模块 a.b.d,将其添加到 sys.modules,执行其代码,将其添加为属性 '模块a.b的d',然后尝试将a.b.d绑定(bind)到名称d但失败。问题是模块 a.b 尚未完成初始化,因此属性“b”不在模块 a 中。

为什么

要理解这一点,您应该知道 import 语句做了两件事(在 Python 2Python 3 中)。

  1. 查找一个或多个模块,并在必要时对其进行初始化;
  2. 在本地命名空间中定义一个名称并将其绑定(bind)到某个模块。

模块查找

前一个调用 __import__ 钩子(Hook),该钩子(Hook)加载模块并初始化它。在 Python 2 中,钩子(Hook)是 imputil.ImportManager._import_hook默认情况下,它的工作方式如下。

  1. 检查模块是否在sys.modules中;
  2. 如果没有,找到该模块并获取其代码;
  3. 创建模块并将其添加到sys.modules
  4. 在模块的命名空间内运行代码;
  5. 退回模块。

如果语句类似于import a.b.c,则模块查找过程将递归查找模块aa.ba.b.c,并在 sys.modules 中跟踪它们。如果返回模块a.b,则将其设置为模块a 的属性“b”。最后,模块查找过程将返回顶层模块a

如果语句类似于 from a.b import c,d,结果会略有不同。在这种情况下,将返回底部模块(即模块a.b)。

名称绑定(bind)

如果使用import [module]语句,顶级模块的名称将绑定(bind)到返回值(即顶级模块)。

如果您使用 import [module] as [name] 语句,则 [name] 将绑定(bind)到底部模块(通过访问顶部模块的属性)模块)。

如果您使用 from [module] import [identifier],那么底部模块的名称将绑定(bind)到返回值(在 from import 语句中是底部模块)。

Example
import a.b.c # a <- <module 'a'>
import a.b.c as c # c <- <module 'a'>.b.c
from a.b import c # c <- <module 'a.b'>.c

在您的问题中,当模块a.b半初始化并且尚未在模块a中注册时,c.py中的导入语句就会发生的属性。所以import as在将a.b.c绑定(bind)到c时会遇到问题。不过,由于模块a.b已经在sys.modules中注册,所以使用from import不会遇到这样的问题。

关于python - 使用绝对导入和__init__.py时是否是循环导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37278101/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com