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

另请参阅:“包”和“模块”之间的区别(对于其他语言)


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

import my_module

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

from my_package.timing.danger.internets import function_of_love

模块文档

软件包简介


任何Python文件都是一个模块,其名称是文件的基本名称,不带.py扩展名。包是Python模块的集合:虽然模块是单个Python文件,但包是包含额外__init__.py文件的Python模块目录,以区分包和恰好包含一堆Python脚本的目录。只要相应的目录包含自己的__init__.py文件,包可以嵌套到任何深度。

模块和包之间的区别似乎只在文件系统级别上存在。当您导入模块或包时,Python创建的相应对象总是模块类型。但是,请注意,当您导入包时,只有该包的__init__.py文件中的变量/函数/类是直接可见的,而不是子包或模块。例如,考虑Python标准库中的xml包:其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编写的,但我不认为您打算在问题中考虑这些模块。


从Python词汇表中:

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

名称中带有破折号的Python文件(如my-file.py)不能用简单的import语句导入。代码方面,importmyfile与importmy-file相同,这会引发异常。这样的文件更好地被描述为脚本,而可导入的文件是模块。


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

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

因此,包实际上是一个分发单元,它提供一个或多个模块。


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

(例如,请注意,根据sys.path和其他设置,可以从同一个文件加载两个不同名称的模块。这正是python-m my.module在解释器中后跟import my.module时所发生的情况;将有两个模块对象__main__和my.modules,它们都是从磁盘上的同一文件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'>

模块a和a.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不是包,因此不能有子模块。

您还可以在这里看到,包模块a具有__path__属性(包必须具有此属性),但非包模块a.b没有。


我读了这个问题的不同答案。这一问题已得到充分解决。但在我看来,多强调一点可能不是一个坏主意。如果我们检查不同模块的__package__值,我们会得到以下结果。所有这些都是模块类型,但其中一些没有定义包。检查__package__的“随机”和“数学”。

import cv2
import math
import random
import tkinter as tk

print('cv2:',type(cv2))             # <class 'module'>
print('cv2:',cv2)                   # <module 'cv2.cv2' from 'PATH'>
print('cv2:',cv2.__package__)       # cv2

print('random:',type(random))       # <class 'module'>
print('random:',random)             # <module 'random' from 'PATH'>
print('random:',random.__package__) # [EMPTY]

print('tk:',type(tk))               # <class 'module'>
print('tk:',tk)                     # <module 'tkinter' from 'PATH'>
print('tk:',tk.__package__)         # tkinter

print('math:',type(math))           # <class 'module'>
print('math:',math)                 # <module 'math' (built-in)>
print('math:',math.__package__)     # [EMPTY]

因此,如果我们按如下方式定义文件夹:

这是我们如何看到__package__输出的:

import myfolder
import myfolder.script1 as s1
import myfolder.script2 as s2
import myfolder.mySubfolder.script3 as s3

print(type(s1)) # <class 'module'>
print(type(s2)) # <class 'module'>
print(type(s3)) # <class 'module'>

print(s1.__package__) # myfolder
print(s2.__package__) # myfolder
print(s3.__package__) # myfolder.mySubfolder

print(myfolder)                     # <module 'myfolder' (namespace)>
print(myfolder.mySubfolder)         # <module 'myfolder.mySubfolder' (namespace)>
print(myfolder.mySubfolder.script3) # <module 'myfolder.mySubfolder.script3' from 'PATH'>

print(myfolder.__package__)                     # myfolder        
print(myfolder.mySubfolder.__package__)         # myfolder.mySubfolder
print(myfolder.mySubfolder.script3.__package__) # myfolder.mySubfolder

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

TL;DR-简短回答:

包也是模块,但它们是其中的一种特殊类型。特别之处在于1。它们是“目录”和2。它们可能包含特殊文件,如__init__.py和__main__.py。

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

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

因此,让我们先从总体上讨论模块,因为它不那么模糊/更容易理解。我们对模块做的基本上有两件事,要么在其他模块中导入它们,要么直接用Python执行它们。

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

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

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

让我们通过一些示例来了解所有这些:

导入模块:

# bar.py

def talk():
    print("bar")
# foo.py

import bar # <-- importing module "bar"

bar.talk() # <-- prints "bar"

执行模块

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

让我们假设上面示例中的foo.py模块是启动程序的主模块。我们可以通过在终端中键入以下命令来运行它:python3foo.py#<--执行一个主模块,然后它将启动我们的程序。

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

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

# bar.py

def talk():
    print("bar")

if __name__ == '__main__':
    talk()

现在在终端中运行这个命令:python3bar.py#<--单独尝试模块的功能,然后它将打印条。

现在,我们知道了如何处理模块,让我们回到主要问题:

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

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

2.常规模块可以“导入”并且可以“执行”(如上面的示例所示),包模块也可以“导入“并且可以“运行”,然而,您可能会正确地抱怨:“但是我们不能直接在目录中编写代码!代码只在文件中编写!”,这确实是一个很好的抱怨,因为它导致了包模块的第二个特殊之处。包模块的代码是在其目录中的文件中编写的,这些文件的名称也是Python保留的。如果要“导入”一个包模块,则必须将其代码放在其目录中的__init__.py文件中;如果要“执行”包模块,必须将其执行代码放在目录中的___main__.py文件夹中。

下面是上面解释的最后一个例子:

# hierarchy of files and folders:
.
├── bar_pack/
│   ├── __init__.py
│   ├── __main__.py
│   foo.py
# bar_pack/__init__.py

def talk():
    print("bar")
# bar_pack/__main__.py

import __init__

__init__.talk()
# foo.py

import bar_pack # <-- importing package module "bar_pack"

bar_pack.talk() # <-- prints "bar"
# Run this command in the terminal:
python3 bar_pack # <-- executing the package module "bar_pack", prints "bar"

我知道,现在太晚了,但对一些人来说,一个简单的答案就足够了:

模块是文件,

包是一个文件夹。


模块:模块是一个简单的Python文件,扩展名为(.py),包含函数和全局变量的集合。它是一个可执行文件,Python中的Package概念用于排列所有模块。

例如:将代码保存在名为demo(module.py)的文件中。

def myModule1(name):
    print("My Module name is: "+ name)

导入演示模块模块并在其中使用myModule1函数。

import demo_module
  
demo_module.myModule1("Math")

解决方案:

我的模块名称是:数学

包:包是包含模块集合的基本目录。该目录包含Python模块以及一个(__init.py__)文件,解释器使用该文件将其识别为包。该包只不过是一个命名空间。在包中,有子包。

例如:

学生(套餐)

|__init__.py(构造函数)

|details.py(模块)

|marks.py(模块)

|collegeDetails.py(模块)

|demo_module.py(模块)

包是一组组织成目录以形成包目录的模块。

from Student import details, collegeDetails, demo_module