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

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

另见:“包”和“模块”有什么区别(其他语言)

323631 次浏览

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

import my_module

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

from my_package.timing.danger.internets import function_of_love

模块文档

软件包简介

任何Python文件都是模块,其名称是没有.py扩展名的文件的基本名称。是Python模块的集合:模块是单个Python文件,包是包含额外__init__.py文件的Python模块目录,以将包与恰好包含一堆Python脚本的目录区分开来。包可以嵌套到任何深度,前提是相应的目录包含自己的__init__.py文件。

模块和包之间的区别似乎只存在于文件系统级别。当你导入一个模块或包时,Python创建的相应对象总是类型为module。然而,请注意,当你导入一个包时,只有该包__init__.py文件中的变量/函数/类是直接可见的,没有个子包或模块。例如,考虑Python标准库中的xml包:它的xml目录包含一个__init__.py文件和四个子目录;子目录etree包含一个__init__.py文件,其中包括一个ElementTree.py文件。看看当你尝试以交互方式导入包/模块时会发生什么:

>>> import xml>>> type(xml)<type 'module'>>>> xml.etree.ElementTreeTraceback (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.ElementTreeTraceback (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词汇表

所有的包都是模块,但并不是所有的模块都是包。或者换句话说,包只是一种特殊的模块。具体来说,任何包含#0属性的模块都被认为是包。

名称中带破折号的Python文件,如my-file.py,不能通过简单的import语句导入。从代码上看,import my-fileimport my - file相同,这将引发异常。此类文件更好地描述为脚本,而可导入文件是模块

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

一个包由一个导入的top实体表示,它可以是是一个自包含的模块,或者__init__.py特殊模块作为从子目录结构中的一组模块中的top实体。

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

首先,请记住,在其精确定义中,模块是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 aa                ⇒ <module 'a' (namespace)>a.b              ⇒ AttributeError: module 'a' has no attribute 'b'import a.b.ca.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 packageimport a.ba                ⇒ <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 cv2import mathimport randomimport 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 myfolderimport myfolder.script1 as s1import myfolder.script2 as s2import myfolder.mySubfolder.script3 as s3
print(type(s1)) # <class 'module'>print(type(s2)) # <class 'module'>print(type(s3)) # <class 'module'>
print(s1.__package__) # myfolderprint(s2.__package__) # myfolderprint(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__)                     # myfolderprint(myfolder.mySubfolder.__package__)         # myfolder.mySubfolderprint(myfolder.mySubfolder.script3.__package__) # myfolder.mySubfolder

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

太长别读-简短回答:

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

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

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

所以让我们先谈谈一般的模块,因为它不那么模糊/更容易理解。我们对模块做的基本上有两件事,我们要么将它们导入其他模块,要么直接由Python执行它们。

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

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

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

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

导入模块:

# bar.py
def talk():print("bar")
# foo.py
import bar # <-- importing module "bar"
bar.talk() # <-- prints "bar"

执行模块

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

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

目标2,孤立地尝试模块的功能:

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

# bar.py
def talk():print("bar")
if __name__ == '__main__':talk()

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

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

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

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"

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

一个模块是一个文件,

一个包是一个文件夹。

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

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

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

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

import demo_module  
demo_module.myModule1("Math")

解决方案:

我的模块名称是:数学

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

举个例子:

学生(套餐)

|__init__.py(构造函数)

|details.py(模块)

|marks.py(模块)

|collegeDetails.py(模块)

|demo_module.py(模块)

包是一组模块,它们被组织成目录,形成一个包目录。

from Student import details, collegeDetails, demo_module