Python 中的模块和包有什么区别?
- 2024-12-20 08:37:00
- admin 原创
- 79
问题描述:
Python 中的模块和包有什么区别?
另请参阅:“包”和“模块”之间有什么区别?(针对其他语言)
解决方案 1:
任何 Python 文件都是一个模块,其名称是文件的基本名称,不带
.py
扩展名。包是Python 模块的集合:模块是单个 Python 文件,而包是包含附加文件的 Python 模块目录,以区分包与恰好包含一堆 Python 脚本的目录。包可以嵌套到任意深度,前提是相应的目录包含自己的文件。
__init__.py
`__init__.py`
模块和包之间的区别似乎只存在于文件系统级别。导入模块或包时,Python 创建的相应对象始终是类型module
。但请注意,导入包__init__.py
时,只有该包文件中的变量/函数/类是直接可见的,而不是 子包或模块。
例子
举个例子,考虑一下xml
Python 标准库中的包:它的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 编写的,但我认为你无意在问题中考虑这些。
解决方案 2:
模块是单个文件(或多个文件),在一次导入下导入并使用。例如
import my_module
包是目录中模块的集合,这些模块构成了包的层次结构。
from my_package.timing.danger.internets import function_of_love
模块文档
包简介
解决方案 3:
首先,请记住,模块的精确定义是 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'>
模块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
没有。
解决方案 4:
来自Python 词汇表:
重要的是要记住,所有包都是模块,但并非所有模块都是包。或者换句话说,包只是一种特殊的模块。具体来说,任何包含
__path__
属性的模块都被视为包。
名称中带有破折号的 Python 文件(如my-file.py
)无法通过简单语句导入import
。从代码角度来看,import my-file
和 相同,这import my - file
将引发异常。此类文件最好被描述为脚本,而可导入文件则是模块。
解决方案 5:
这里的其他答案可能仍然有点模糊,所以我发布了一个希望更清晰的答案。重要的是要注意,问题的标题首先也有点误导,我认为更好的标题是:“与常规模块相比,包模块有什么特别之处? ”。
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
上面例子中的模块是启动我们程序的主模块。我们可以通过在终端中输入此命令来运行它:python3 foo.py # <-- executing a main module
然后它将启动我们的程序。
目标 2,单独尝试模块的功能:
假设我们想尝试上面示例中模块talk
中的函数,而不运行整个程序,即不调用模块。为此,我们必须稍微改变:bar.py
`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"
解决方案 6:
迟来的答案,还有另一个定义:
包由导入的顶级实体表示,它可以是自包含模块,也可以
__init__.py
是作为子目录结构中的一组模块的顶级实体的特殊模块。
因此,从物理上讲,包是一个分发单元,它提供一个或多个模块。
解决方案 7:
模块:模块是一个简单的 Python 文件,带有 ( .py
) 扩展名,其中包含函数和全局变量的集合。它是一个可执行文件,Python 中的包概念用于安排所有模块。
举例来说:将代码保存在名为 demo ( module.py
) 的文件中。
def myModule1(name):
print("My Module name is: "+ name)
导入演示模块module并使用其中的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
解决方案 8:
我阅读了对这个问题的不同回答。这个问题已经完全涵盖了。但在我看来,再加一点可能不是一个坏主意。如果我们检查不同模块的package值,我们会得到以下结果。它们都是模块类型,但其中一些模块的包没有定义。检查package中是否有“ random ”和“ math ”。
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
解决方案 9:
下面简单说一下文档中模块和包中的内容:
模块是一个文件或包(文件夹)。
包是一个可以有多个模块(文件和包(文件夹))的模块。
而且,这就是文档在模块中实际所说的内容:
作为 Python 代码组织单元的对象。模块具有包含任意 Python 对象的命名空间。模块通过导入过程加载到 Python 中。
而且,这就是文档在下面的包中实际所说的内容:
可以包含子模块或递归子包的 Python 模块。从技术上讲,包是具有路径属性的 Python 模块。
最后,您可以看到我的答案,解释如何创建模块(文件和包),您可以看到我的答案,解释如何为TestPyPI和PyPI创建、上传和安装包
解决方案 10:
我知道,已经太晚了,但对于一些人来说,一个简单的答案就足够了:
一个模块就是一个文件,
包就是一个文件夹。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理必备:盘点2024年13款好用的项目管理软件