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


575

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

另请参阅:“程序包”和“模块”之间有什么区别(对于其他语言)


9
我可能错了,但对我来说:模块基本上是一个python文件。包是带有一堆模块(python文件)的文件夹。
lc2817 2011年

36
要被视为软件包,该文件夹必须包含一个__init__.py文件。
Giulio Piancastelli,

@ lc2817:这是最常见的情况,但是没有必要从文件系统中加载模块,例如,参见from plumbum.cmd import ls实现
jfs 2015年

4
@GiulioPiancastelli:在Python 3.3+中,名称空间包不使用__init__.py
jfs

社区如何区分Python程序包和用于分发Python组件(如PyPI / wheels / etc)的程序包?在我看来,这两个词似乎像“包装”一词的不同用法。
davidA

Answers:


372

模块是在一个导入下导入并使用的单个文件。例如

import my_module

软件包是目录中提供软件包层次结构的模块的集合。

from my_package.timing.danger.internets import function_of_love

模块文档

套餐介绍


54
当您说:“一个模块是在一个导入下导入的单个文件(或多个文件)”时,您能解释一个模块有多个文件的情况吗?还是我误读了你的意思?
用户

5
您不需要文件来创建模块,例如,您可以从zip文件中导入模块。包也一样。Python中的模块/包只有一个类。包只是具有__path__属性的模块。
jfs 2015年

33
也是模块。它们只是包装不同而已。它们由目录加__init__.py文件的组合形成。它们是可以包含其他模块的模块。
马丁·彼得斯

15
@Jacquot,请参见参考文档中的导入系统:请务必牢记所有软件包都是模块
马丁·彼得斯

6
@Jacquot:和“ package”上词汇表Python模块,可以包含子模块或递归地包含子包。从技术上讲,包是具有__path__属性的Python模块。
马丁·彼得斯

556

任何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>

在Python中,还有一些内置模块(例如)sys,这些模块都是用C语言编写的,但我认为您并不是要考虑问题中的那些模块。


9
感谢您明确提及Python创建的相应对象始终是type module。我正在编写调试器,并且担心调试器说我的软件包是modules 是不正确的。
ArtOfWarfare 2015年

8
@jolvi的文件名包含破折号的Python文件仍可以作为模块导入,只是不能使用通常的import语句,因为Python标识符中不允许使用破折号。使用importlib.import_module()代替。
朱利奥·皮安卡斯特利

2
@jolvi我不是。您在哪里读到我的评论?我只是说,如果您碰巧或偶然发现名称中带有破折号的Python文件,您仍然可以将其作为模块导入。我没有发表有关命名Python文件的首选方式的声明。我相信您可以在其他地方找到它:通常强烈建议您避免使用下划线来代替下划线。
Giulio Piancastelli,2016年

3
对Python来说,新的子包或模块在导入父包时默认不可用,这让我感到迷惑。是否有特定原因?在导入父包时,是否有一个通用的模式如何使子包或模块可用(通过其完全限定的名称)?
sschuberth

2
@sschuberth只需将子包导入父包的init .py中即可。
安娜

33

Python词汇表中

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

名称中带有破折号的Python文件(如my-file.py)无法通过简单的import语句导入。代码明智的,import my-file是一样的import my - file,这将引发异常。这样的文件可以更好地描述为脚本,而可导入文件是模块


23

首先,请记住,按照其精确定义,模块是Python解释器内存中的对象,通常是通过从磁盘读取一个或多个文件来创建的。虽然我们可以非正式地称呼磁盘文件(例如a/b/c.py“模块”),但实际上它并没有与其他来自其他来源(例如sys.path)的信息组合在一起以创建模块对象,而是变成一个文件。

(例如,请注意,可以根据相同的sys.path设置和其他设置,从同一个文件中加载名称不同的两个模块。这正是在解释器中python -m my.module后面跟着的情况import my.module;将有两个模块对象,__main__并且my.module都创建了来自磁盘上的同一文件,my/module.py。)

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

$ mkdir -p a/b
$ touch a/b/c.py

确保下没有其他文件a。启动Python 3.4或更高版本的解释器(例如,使用python3 -i)并检查以下语句的结果:

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'>

模块aa.b是程序包(实际上,一种程序包称为“命名空间程序包”,尽管我们在这里不必担心)。但是,模块a.b.c不是包。我们可以通过a/b.py在上面的目录结构中添加另一个文件并启动一个新的解释器来演示这一点:

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__'

Python确保在加载子模块之前先加载所有父模块。在其上方找到a/一个目录,因此创建了一个名称空间包a,这a/b.py是一个Python源文件,它被加载并用于创建(非包)模块a.b。此时,您无法拥有模块,a.b.c因为a.b它不是软件包,因此不能拥有子模块。

您还可以在此处看到package模块a具有__path__属性(packages必须具有此属性),但非package模块a.b则没有。


1
如果还没有,请返回并通过此答案中的示例进行操作。
Donal Lafferty

2

一个较晚的答案,还有另一个定义:

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

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


1
我觉得Python中的package有两个定义,它们是不同的。您的答案似乎将它们结合在一起。严格来说,python软件包是一个__init__.py内部带有模块的目录,但是,如果您谈论分发单元(通常通过PyPI),那么这完全是另一种类型的软件包(通常由的存在来定义setup.py)。我发现该术语的这两种用法package令人困惑,并且我已经与一些Python初学者进行了交谈,他们发现它完全令人困惑。
davidA

@davidA,这不只是您的感受。它已经被编纂为:Packaging.python.org/glossary/#term-distribution-package(也感谢您澄清!)
Lorem Ipsum

0

包也是一个模块,可以包含其他模块,“基于文件的简单模块和包(子包)”。与模块的包装类型相关的代码进入该__init__.py文件。

import pack1
print(type(pack1))

而模块是一个简单的文件,可以包含函数,类,可运行代码等。导入模块后,它的行为就像一个对象,您可以通过该对象访问模块中定义的标识符。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.