从一个包中导入模块的Python语法

15

文件夹结构:

<current dir>
   main.py
   packages <dir>
      __init__.py
      mod.py

主py文件:

import packages
print packages.mod.hello()

mod.py:

def hello():
    return 'hello'

__init__.py:

from packages import mod

如果我运行main.py,就不会出现错误。但如果我编辑__init__.py'from packages import *',我会得到这个错误:AttributeError:'module'对象没有属性'mod'

我不是在问如何使那个'print'命令工作。我可以在main.py中使用其他'import'语法使其工作。问题是:我对'from packages import mod'__init__.py中感到好奇。如果我可以做import mod,那么当我替换为import *时,也就是导入所有内容,为什么我会遇到错误呢?

那么,在__init__.py中的from packages import *真正意味着什么?

有人能帮忙吗?谢谢

3个回答

23

简短回答

那么在__init__.py中,from packages import *实际上意味着什么?

__init__.py导入了它本身。

解释

你只能导入模块,而不能导入包。包只是模块或子包的容器。当你“导入”一个包时,实际上导入的是模块__init__.py

这是__init__.py的内容:

from packages import mod

将模块mod导入到__init__.py中。因此,通过packages.modmain.py中可以使用它(请记住packages__init__.py表示)。
当您更改__init__.py的内容时:
from packages import *

你正在导入模块__init__.py,这个文件和你当前所在的文件是完全相同的。这样做可以工作(第二次导入只会触发在sys.modules中查找),但不会给你mod的内容。
这意味着你可以使用:
from module import *

但是如果一个__init__.py文件为空,你就不能明智地使用它:

from package import *

由于package实际上是由__init__.py表示的,而且里面还没有任何内容。您可以检查这一点(交互式或在文件中):
>>> import packages
>>> print(packages)
<module 'packages' from '/.../packages/__init__.py'>

__init__.py中,您可以编写:
from packages.mod import *

然后在 main.py 中:
print packages.hello()

工作原理。因为函数hello()现在位于文件__init__.py的全局命名空间中。

正如mozman的回答中所提到的,您可以在__init__.py中使用__all__列出模块,如果使用from packages import *,则应该被导入。这是为这种情况而设计的。

__init__.py仅包含此内容:

__all__ = ['mod']

现在你可以在 main.py 中这样做:
from packages import *

print mod.hello()

如果您扩展您的__init__.py:
__all__ = ['mod']

from packages import *

你可以在main.py中完成这个操作:
import packages

print packages.mod.hello()

但是如果你从__init__.py中删除from packages import *

__all__ = ['mod'] 

你会收到一个错误:

AttributeError: 'module' object has no attribute 'mod'

因为__all__仅用于from packages import *的情况。 现在我们回到__init__.py导入自身。

我可以使用 from package import * 这个命令,因为编译时不会出现错误,只有在打印时才会显示“没有模块'mod'”。所以这个命令是有效的,只是我对代码的作用感到困惑。 - andio
“你只能导入模块,而不能导入包”,这表明包和模块是互斥的。然而,在 Python 语言参考文档的 §5.2 包 中指出:“所有的包都是模块,但并不是所有的模块都是包…… 包只是一种特殊的模块。” 此外,一个包可以被导入:“当一个普通的包被导入时,它的 __init__.py 文件会被隐式地执行,并且它定义的对象会绑定到包命名空间中的名称上。” - Jim Ratliff
当你“导入”一个包时,实际上是在导入模块__init__.py。这本质上就是你所说的,不是吗? - Mike Müller

1

另请参阅:Python中的“import *”到底导入了什么?

在packages.__init__中添加__all__:

__all__ = ['mod']
from packages import *

如果导入模块'mod',则会被导入,否则'mod'不在'packages'的命名空间中,但我无法解释为什么没有__all__的'import *'不会导入'mod'。

我会查看链接并进行研究。如果有了结果,我会回来的。 - andio
谢谢,但还有些东西缺失了,这是我得到的内容...如果定义了__all__,则应该导入此序列中定义的所有名称,否则将导入所有名称,除了以一个下划线开头的名称。所以在我的情况下,如果我没有定义__all__,它应该导入所有名称,包括我的'mod',对吗? - andio

0

你可以直接在同一包中加载模块。以下代码有效,并且它会加载 mod.py 中的所有模块。

在 __init__.py 中

from mod import *
print hello()

高效导入 - 仅加载 hello 函数

from mod import hello
print hello()

在你的代码中,from packages import * 你告诉解释器在 packages(与 __init__.py 在同一目录下)中查找模块。但是它并不存在那里。它存在于 __init__.py 上一级目录。(我怀疑我的术语不正确)
这里有一个参考链接,解释了如何加载包本身。 找到了 阅读关于Python导入机制的文章非常有趣。Ref1 Ref2 Ref3

显然,首先加载父模块。例如,Ref3指出,__init__.py中的import mod代码将自动解释为packages.mod。现在我必须找出如果写入import packages.mod会发生什么。 Ref1符合python3规范。有关更多信息,请参考它。希望这可以帮助您。


谢谢,但那不是我的问题,我可以使用其他导入语法使打印工作。但我正在询问的是应该包括所有内容的 import *,包括 ** mod **。 - andio
你说模块名为“packages”的模块不存在,但实际上如果我这样做:从“packages”导入“mod”,它是可以工作的!尝试删除此代码并运行它,它会给你错误。但是当我放置“from packages import mod”时,它就可以工作。所以这意味着它在那里。我知道你的意思,即“packages”是上一级,这就是我困惑的原因。它应该是“非法”的,但是“from packages import mod”却可以工作!这就是我困惑的原因。我可能会稍微改变我的问题...那么为什么“from packages import mod”可以工作? - andio
好的,很有趣。您能指定平台操作系统和Python版本,这样我就可以重现场景并进行测试。我会检查它。 - Mitty
@andio添加了一些参考资料,我仍然需要重新创建您的场景。 - Mitty
@andio 我在指定packages作为根文件夹的IDE中测试了相同的代码。现在from packages import modfrom packages.mod import *都可以工作。但是在终端中运行_init__.py会抛出ImportError: No module named 'packages'。这已经在参考文献1、2和3中详细讨论过了。在调用导入之前,无法知道packages。因此,当我们尝试从packages加载时,它会说ImportError - Mitty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接