Python模块和Python包之间有什么区别?

Dav*_*ave 511 python module package

Python模块和Python包之间有什么区别?

另请参阅:"package"和"module"之间的区别(对于其他语言)

Giu*_*lli 511

任何Python文件都是一个模块,它的名称是文件的基本名称而没有.py扩展名.甲是Python模块的集合:而一个模块是一个Python文件,一个包是含有一个额外的Python模块的目录__init__.py文件中,一个包从恰好包含一堆Python脚本的一个目录区分开.如果相应的目录包含自己的__init__.py文件,则包可以嵌套到任何深度.

模块和包之间的区别似乎只适用于文件系统级别.导入模块或包时,Python创建的相应对象始终为类型module.但是,请注意,导入包时,只能__init__.py直接看到该包文件中的变量/函数/类,而不是子包或模块.例如,考虑xmlPython标准库中的包:其xml目录包含一个__init__.py文件和四个子目录; 子目录etree包含一个__init__.py文件,以及一个ElementTree.py文件.看看当您尝试以交互方式导入包/模块时会发生什么:

>>> import xml
>>> type(xml)
<type 'module'>
>>> xml.etree.ElementTree
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'etree'
>>> import xml.etree
>>> type(xml.etree)
<type 'module'>
>>> xml.etree.ElementTree
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'ElementTree'
>>> import xml.etree.ElementTree
>>> type(xml.etree.ElementTree)
<type 'module'>
>>> xml.etree.ElementTree.parse
<function parse at 0x00B135B0>
Run Code Online (Sandbox Code Playgroud)

在Python中还有内置模块,例如sys,用C语言编写,但我认为你不打算考虑那些问题.

  • @jolvi具有包含破折号的文件名的Python文件仍然可以作为模块导入,而不是使用通常的`import`语句,因为Python标识符中不允许使用破折号.请改用"importlib.import_module()". (8认同)
  • 感谢您明确提到Python创建的相应对象始终是`module`类型.我正在编写一个调试器,并担心我的调试器不正确,说我的软件包是`module`s. (6认同)
  • 作为Python的新手,在导入父包时默认不可用的子包或模块是让我绊倒的原因.这有什么特别的原因吗?在导入父包时,是否有一个共同模式如何*使*子包或模块可用(通过其完全限定名称)? (3认同)
  • @sschuberth 只需在父包的 __init__.py 中导入子包。 (3认同)
  • @jolvi我不是.你在评论中读到的是什么?我只是说,如果您碰巧遇到或偶然发现了名称中带有破折号的Python文件,您仍然可以将其作为模块导入.我没有说明命名Python文件的首选方法.我相信你可以在其他地方找到它:通常强烈建议避免使用破折号来支持下划线. (2认同)
  • @sschuberth 绝对。但是,第三方包作者可能会在他们的包中包含这样的导入。(PS 我当然是指`__init__.py`。) (2认同)

Jak*_*yer 331

模块是在一个导入下导入并使用的单个文件(或多个文件).例如

import my_module
Run Code Online (Sandbox Code Playgroud)

包是给出包层次结构的目录中的模块的集合.

from my_package.timing.danger.internets import function_of_love
Run Code Online (Sandbox Code Playgroud)

模块文档

包介绍

  • 当您说:"模块是在一个导入下导入的单个文件(或多个文件)"时,您能解释一个模块是多个文件的情况吗?或者我误读了你的意思? (47认同)
  • 根据文档,模块是单个文件.没有任何地方说多个文件可以是一个模块. (32认同)
  • 包*也是模块*.它们的封装方式不同; 它们是由目录和`__init __.py`文件的组合形成的.它们是可以包含其他模块的模块. (25认同)
  • @Jacquot肯定,请参阅参考文档中的[*导入系统*](https://docs.python.org/3/reference/import.html#packages):*请务必记住所有包都是模块*. (13认同)
  • @Jacquot:和[词汇表"包"](https://docs.python.org/3/glossary.html#term-package):*一个Python模块,可以包含子模块或递归的子包.从技术上讲,包是一个带有`__path__`属性的Python模块.* (6认同)
  • 您不需要文件来创建模块,例如,您可以从zip文件导入模块.包裹也一样.Python中的模块/包只有一个类.包只是一个带有__path__`属性的模块. (5认同)
  • @MartijnPieters您是否有一个链接来支持程序包也是模块?我同意mareofraft以及模块是单个文件的文档。你的话即使是真的也只会增加混乱 (3认同)
  • @OldGeezer:那么它就不能是包,因为名称必须是有效的 Python 标识符。这同样适用于字母、数字和下划线之外的任何其他字符。 (2认同)
  • 根据 [PEP8](https://www.python.org/dev/peps/pep-0008/#package-and-module-names),不鼓励在包命名中使用下划线 (2认同)
  • @Jacquot:仍然只有一个文件; `__ init __.py`,子模块是包目录中的单独文件(包括更多包). (2认同)
  • 那么在您的示例中,“timing”是子模块还是子包? (2认同)

jol*_*lvi 30

Python术语表:

重要的是要记住所有包都是模块,但并非所有模块都是包.换句话说,包只是一种特殊的模块.具体而言,包含__path__属性的任何模块都被视为包.

名称中包含破折号的Python文件my-file.py无法使用简单import语句导入.代码方式import my-fileimport my - file引发异常的方式相同.这些文件更好地表征为脚本,而可导入文件是模块.


ade*_*hox 22

这里的其他答案可能仍然有点模糊,所以我发布了一个希望更清晰的答案。需要注意的是,问题的标题首先也有点误导,我认为更好的标题是:与常规模块相比,包模块有什么特别之处?

\n

TL;DR - 简短回答:

\n

包也是模块,但是它们是模块的一种特殊类型。特殊是指1.它们是“目录”并且2.它们可能包含特殊文件,例如__init__.py__main__.py

\n

为了更好地理解 - 更长的答案:

\n

重点是,包是一种特殊类型的模块,因此我们需要首先了解一般的模块,然后再了解包模块的特殊之处也就有意义了。(注意:我有时会在这个答案中将“包模块”称为“包”,反之亦然)

\n

因此,让我们首先讨论一下一般的模块,因为它不会那么模糊/更容易理解。我们对模块基本上做了两件事,要么将它们导入到其他模块中,要么直接通过 Python 执行它们。

\n

导入模块有一个明显的目标,即访问该模块内部的内容。

\n

然而,执行模块通常会追求以下两个目标之一:

\n
    \n
  1. 该模块是主模块,执行它将启动我们的程序(或其子程序之一)。
  2. \n
  3. 我们希望单独尝试该模块的功能,即无需先导入它。
  4. \n
\n

让我们通过一些例子来更好地理解所有这些:

\n

导入模块:

\n
# bar.py\n\ndef talk():\n    print("bar")\n
Run Code Online (Sandbox Code Playgroud)\n
# foo.py\n\nimport bar # <-- importing module "bar"\n\nbar.talk() # <-- prints "bar"\n
Run Code Online (Sandbox Code Playgroud)\n

执行模块

\n

目标 1,将模块作为主模块执行:

\n

我们假设foo.py上面示例中的模块是启动我们的程序的主模块。我们可以通过在终端中输入以下命令来运行它:python3 foo.py # <-- executing a main module然后它将启动我们的程序。

\n

目标 2,单独尝试模块的功能:

\n

假设我们想尝试上面示例中 moduletalk中的函数bar.py,而不运行整个程序,即不调用 module foo.py。为此,我们必须稍微改变bar.py

\n
# bar.py\n\ndef talk():\n    print("bar")\n\nif __name__ == \'__main__\':\n    talk()\n
Run Code Online (Sandbox Code Playgroud)\n

现在在终端中运行此命令:python3 bar.py # <-- trying functionalities of a module in isolation然后它将打印bar

\n

现在我们知道了一般可以用模块做什么,让我们回到主要问题:

\n

与常规模块相比,包模块有什么特别之处?

\n

1. Python 中的常规模块只是“文件”,而包模块则是“目录”。

\n

2. 常规模块可以“导入”并且可以“执行”(如上面的示例所示),包模块也可以“导入”并且可以“执行”,但是,您可能会抱怨:“但是我们可以\不能直接在目录中写入代码!代码只能写入文件中!” ,这确实是一个非常好的抱怨,因为它引导我们了解关于包模块的第二个特殊的事情。包模块的代码写在其目录内的文件中,这些文件的名称也是Python保留的。如果你想“导入”一个包模块,你必须将其代码放在__init__.py其目录中的一个文件中,如果你想“执行”一个包模块,你必须将执行代码它位于__main__.py其目录中的一个文件中。

\n

这是上述解释的最后一个示例:

\n
# hierarchy of files and folders:\n.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar_pack/\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __main__.py\n\xe2\x94\x82   foo.py\n
Run Code Online (Sandbox Code Playgroud)\n
# hierarchy of files and folders:\n.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar_pack/\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 __main__.py\n\xe2\x94\x82   foo.py\n
Run Code Online (Sandbox Code Playgroud)\n
# bar_pack/__init__.py\n\ndef talk():\n    print("bar")\n
Run Code Online (Sandbox Code Playgroud)\n
# bar_pack/__main__.py\n\nimport __init__\n\n__init__.talk()\n
Run Code Online (Sandbox Code Playgroud)\n
# Run this command in the terminal:\npython3 bar_pack # <-- executing the package module "bar_pack", prints "bar"\n
Run Code Online (Sandbox Code Playgroud)\n


Cur*_*son 18

首先,请记住,在精确定义中,模块是Python解释器内存中的对象,通常通过从磁盘读取一个或多个文件来创建.虽然我们可以非正式地调用诸如a/b/c.py"模块"之类的磁盘文件,但在与来自其他几个源(例如sys.path)的信息组合以创建模块对象之前,它实际上不会成为一个.(例如,注意,可以从同一文件加载具有不同名称的两个模块,具体取决于sys.path其他设置.)

是可以具有子模块(包括子包)的模块.并非所有模块都能做到这一点.例如,创建一个小模块层次结构:

$ mkdir -p a/b
$ touch a/b/c.py
Run Code Online (Sandbox Code Playgroud)

确保下面没有其他文件python -m my.module.启动Python 3.4或更高版本的解释器(例如,with import my.module)并检查以下语句的结果:

import a
a                ? <module 'a' (namespace)>
a.b              ? AttributeError: module 'a' has no attribute 'b'
import a.b.c
a.b              ? <module 'a.b' (namespace)>
a.b.c            ? <module 'a.b.c' from '/home/cjs/a/b/c.py'>
Run Code Online (Sandbox Code Playgroud)

模块__main__my.module包(事实上,某种类型的包被称为"命名空间包",虽然我们不担心这里).但是,模块my/module.py不是包.我们可以通过a在上面的目录结构中添加另一个文件并启动一个新的解释器来证明这一点:

import a.b.c
? ImportError: No module named 'a.b.c'; 'a.b' is not a package
import a.b
a                ? <module 'a' (namespace)>
a.__path__       ? _NamespacePath(['/.../a'])
a.b              ? <module 'a.b' from '/home/cjs/tmp/a/b.py'>
a.b.__path__     ? AttributeError: 'module' object has no attribute '__path__'
Run Code Online (Sandbox Code Playgroud)

Python确保在加载子模块之前加载所有父模块.在它上面发现它python3 -i是一个目录,因此创建了一个命名空间包a,它a.b是一个Python源文件,它加载并用于创建(非包)模块a.b.c.此时你不能拥有一个模块,a/b.py因为a/它不是一个包,因此不能有子模块.

您还可以在此处看到包模块a具有a/b.py属性(包必须具有此属性),但非包模块a.b不具有此属性.

  • 如果您还没有这样做,请返回并完成此答案中的示例。 (3认同)

小智 5

迟到的答案,还有另一个定义:

包由导入的顶级实体表示,该实体可以是独立的模块,也可以__init__.py是作为子目录结构中一组模块中的顶级实体的特殊模块。

因此,从物理上来说,包是一个分发单元,它提供一个或多个模块。

  • 我觉得 Python 中 _package_ 有两种定义,它们是不同的。你的回答似乎将它们结合在一起。严格来说,Python 包是一个内部包含 `__init__.py` 模块的目录,但如果你谈论分发单元(通常通过 PyPI),那么这完全是另一种类型的包(通常由 `setup.py` 的存在来定义) `)。我发现术语“package”的这两种用法令人困惑,并且我与一些 Python 初学者交谈过,他们发现它完全令人困惑。 (5认同)
  • @davidA,这不仅仅是你的感受。它已被编纂:https://packaging.python.org/glossary/#term-distribution-package(也感谢您的澄清!) (2认同)