为什么这两个 Python 导入的工作方式不同?

发布于 2024-11-24 09:23:44 字数 1041 浏览 2 评论 0原文

假设以下代码结构:

#### 1/hhh/__init__.py: empty

#### 1/hhh/foo/__init__.py:
from hhh.foo.baz import *

#### 1/hhh/foo/bar.py:
xyzzy = 4

#### 1/hhh/foo/baz.py:
import hhh.foo.bar as bar
qux = bar.xyzzy + 10

我在 1/ 内运行 python 并执行 import hhh.foo.baz。它失败了:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "hhh/foo/__init__.py", line 1, in <module>
    from hhh.foo.baz import *
  File "hhh/foo/baz.py", line 1, in <module>
    import hhh.foo.bar as bar
AttributeError: 'module' object has no attribute 'foo'

现在我将 baz.py 替换为:

# 1/hhh/foo/baz.py:
from hhh.foo.bar import xyzzy
qux = xyzzy + 10

并再次执行import hhh.foo.baz。现在它可以工作了,尽管我正在加载相同的模块,只是绑定了不同的名称。

这是否意味着 import modulefrom module import name 之间的区别不仅仅是标识符?这里究竟发生了什么?

(我知道我可以使用相对导入来解决所有这些问题,但我仍然想了解其机制。另外,我不喜欢相对导入,PEP 8 也不喜欢。)

Assume the following code structure:

#### 1/hhh/__init__.py: empty

#### 1/hhh/foo/__init__.py:
from hhh.foo.baz import *

#### 1/hhh/foo/bar.py:
xyzzy = 4

#### 1/hhh/foo/baz.py:
import hhh.foo.bar as bar
qux = bar.xyzzy + 10

I run python inside 1/ and do import hhh.foo.baz. It fails:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "hhh/foo/__init__.py", line 1, in <module>
    from hhh.foo.baz import *
  File "hhh/foo/baz.py", line 1, in <module>
    import hhh.foo.bar as bar
AttributeError: 'module' object has no attribute 'foo'

Now I replace baz.py with:

# 1/hhh/foo/baz.py:
from hhh.foo.bar import xyzzy
qux = xyzzy + 10

and again do import hhh.foo.baz. Now it works, although I’m loading the same module, only binding a different name.

Does this mean that the distinction between import module and from module import name goes beyond just identifiers? What exactly is going on here?

(I know I can use relative imports to work around all this, but still I’d like to understand the mechanics. Plus I don’t like relative imports, and neither does PEP 8.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

第几種人 2024-12-01 09:24:29

为什么要从 hhh.foo.bar 导入 hhh.foo? import bar 应该足够了。

Why do you import from hhh.foo.bar in hhh.foo? import bar should suffice there.

嘿哥们儿 2024-12-01 09:24:28

1/hhh/foo/__init__.py 中,您需要使用要导出的名称设置 __all__ 列表。即 __all__ = ["xyzzy"]

in 1/hhh/foo/__init__.py you need to set the __all__ list with the names of what you want to export. i.e. __all__ = ["xyzzy"]

情话已封尘 2024-12-01 09:24:27

当您编写 from hhh.foo.bar import xyzzy 时,Python 解释器将尝试从模块 hhh.foo.bar 加载 xyzzy。但是,如果您编写 import hhh.foo.bar as bar ,它会首先尝试在 hhh.foo 模块中查找 bar 。因此它评估 hhh.foo,执行 from hhh.foo.baz import *
hhh.foo.baz 尝试评估 hhh.foohhh.foo 尝试评估 hhh.foo.baz >,循环导入,例外。

When you write from hhh.foo.bar import xyzzy Python interpreter will try to load xyzzy from module hhh.foo.bar. But if you write import hhh.foo.bar as bar it will try first to find bar in hhh.foo module. So it evaluates hhh.foo, doing from hhh.foo.baz import *
. hhh.foo.baz tries to evaluate hhh.foo, hhh.footries to evaluate hhh.foo.baz, cyclic imports, exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文