python中的模块库包的区别
python中的模块、库、包有什么区别?
Author: [风影忍着]
Link: [https://www.zhihu.com/question/30082392/answer/2030353759]
一、模块(module)
模块,英文为Modules,本质上是一个Python程序,以.py作为文件后缀。任何py文件都可以作为一个模块。
*其他可作为module的文件类型还有".so"、".pyo"、".pyc"、".dll"、".pyd",但Python初学者几乎用不到。
通过使用模块,可以有效地避免命名空间的冲突,可以隐藏代码细节让我们专注于高层的逻辑,还可以将一个较大的程序分为多个文件,提升代码的可维护性和可重用性。
(一)导入
导入一个模块一般有两种方法:
- import 模块名1 [as 别名1], 模块名2 [as 别名2],…。此时,模块名1本身被导入,但保存它原有的命名空间,所以我们需要用”模块名1.成员名1“方式访问其函数或变量。
- from 模块名 import 成员名1 [as 别名1],成员名2 [as 别名2],…。此时,会将该模块的函数/变量导入到当前模块的命名空间中,无须用“模块名1.成员名1"访问了。
其中,用 [] 括起来的部分,可以使用,也可以省略。
注意,模块名里面只要写py文件的名字,不需要加后缀。
另外,尽量不要使用
from demo import *
的方式进行导入,否则很容易出现名称重复的情况。
例如,如果有两个模块里面有相同的成员,或者你自己定义了某一个对象和demo module里面的成员(例如函数)重名了,运行的时候会出问题。因为此时我们无法确认,我们所指的是自己定义的对象还是demo module里面的成员。
(二)if __name__ == '__main__':
在完成一个模块的编写之前,我们一般会对模块中的功能进行测试,看看各项功能是否正常运行。对于这些测试的代码,我们希望只在直接运行这个py文件的时候执行,在用其他的程序import这个模块的时候不要执行。这个时候就要借助Python内置的__name__变量。
__name__变量的取值是什么可以分两种情况,
- 当一个py文件被直接运行的时候,__name__变量的值为__main__。
- 当一个py文件被import到其他程序的时候,这个py文件里面的__name__变量的值为这个py文件的名字。
我们可以利用__name__变量的这个特点,结合一个if语句,让我们import某一个模块的时候只用到它提供的功能,而不要运行里面用来测试的代码:
if __name__ == '__main__':
# put your code here
2
(三)模块的说明文档
模块的说明文档放在py文件的开头,用成对的三个英文单引号引起来:
'''
模块的说明文档放在这里。
'''
2
3
然后我们可以用模块的__doc__属性来访问模块的说明文档:
import demo
print(demo.__doc__)
2
在调用这个模块来写代码的时候,也可以阅读到模块的说明文档。例如下图,我把鼠标放在导入的 re 包名称上面就能看到其说明文档:
在编程中显示的说明文档的内容和原始 py 文件中的内容一样。例如,下面是 re 模块的原始 py 文件中的说明文档:
(四)模块的路径
对于用import语句导入的模块,Python会按照下面的路径列表顺序地查找我们需要的模块:
- 当前的工作目录;
- PYTHONPATH(环境变量)中的每一个目录;
- Python 默认的安装目录。
如果我们在导入自己写的模块的时候,Python解释器提示找不到这个模块
ModuleNotFoundError: No module named '模块名'
那么,说明我们写的模块没有放在上述三类路径。由于这三类目录都保存在标准模块sys的sys.path变量中,因此我们有三种解决方法。
1.向sys.path变量中临时添加模块文件所在的完整路径。
import sys
sys.path.append(r'D:\xxx\yyy')
2
2.将模块移动到sys.path 变量中已包含的路径中。
3.修改path 系统的环境变量。
其中,环境变量又分为用户变量(仅对当前用户生效)和系统变量(对系统里所有用户均生效)。Python在使用path变量时,会先按照系统path变量找,然后按照用户path变量的路径找。
通常情况下,设置用户path变量即可。
二、包(package)
在比较大型的项目中常常需要编写、用到大量的模块,此时我们可以使用包(Package)来管理这些模块。
(一)什么是包?
Python包,就是里面装了一个__init__.py文件的文件夹。
__init__.py文件(前后各有 2 个下划线'_')具有下面4个性质:
- 它本身是一个模块;
- 这个模块的模块名不是__init__,而是这个包的名字,也就是装着__init__.py文件的文件夹的名字。
- 它的作用是将一个文件夹变为一个Python模块
- 它可以不包含代码,不过此时仅仅用import [该包]形式是什么也做不了的。所以一般会包含一些Python初始化代码,在这个包被import的时候,这些代码会自动被执行。
- 第4点所指的初始化代码类型一:批量导入我们需要用到的模块,这样我们就不用在用到的时候再一一导入,方便实用。
- 第4点所指的初始化代码类型二:如果我们要使用“from pacakge_1 import *”的形式导入一个模块里面的所有内容,则需在__init__.py中加上“all = [‘file_a’, ‘file_b’]”。其中,package_1下有file_a.py和file_b.py。
- 不建议在__init__.py中写类,以保证该py文件简单。
__all__是Python中的一个重要的变量,放在__init__模块中,用于指定此包(package)被import *时,哪些模块(module)会被import进当前作用域中。不在 __all__列表中的模块不会被其他程序引用。我们可以对 __all__进行重写。
__path__也是python中的一个常用变量,它是储存着当前包内的搜索路径的一个列表。默认情况下只有一个元素,即当前包(package)的路径。
Python包具有下面3个性质:
- 它实质上是一个文件夹;
- 该文件夹里面一定有__init__.py模块,其他的模块可以有也可以没有;
- 它的本质依然是模块,因此一个包里面还可以装其他的包。
(二)导入包
导入包的方法和导入模块比较类似,只不过由于层级比一般模块多了一级,所以多了一条导入形式:
- import 包名[.模块名 [as 别名]]
- from 包名 import 模块名 [as 别名]
- from 包名.模块名 import 成员名 [as 别名]
我们在导入包的时候,实际上是导入了它的__init__.py文件文件。
最后总结一下,Python里面存在这样的关系:
数据可以封装在容器(列表、元组、字符串、字典)里面;
代码可以封装在function里面;
function和数据可以封装在class里面(或者说方法和属性可以封装在类里面);
上述三类内容可以打包在module(模块)里面;
多个module可以打包在package(包)里面;
多个package可以打包在library(库)里面。
此外,关于“库(library)”的概念:
https://www.zhihu.com/people/29a618a6a8a39a1683934e8436a1aaf4 (opens new window) 在评论区对于“库(library)”的概念做了很好的补充,使得这篇科普更加的完整。请观众老爷移步评论区,阅读本文唯一的一条精选评论。
https://www.zhihu.com/people/5f4b043a1b4b317a293982593a443b1d (opens new window) https://www.zhihu.com/question/30082392/answer/2315826832 (opens new window),在文末的部分,将库 (library) 和框架 (framework) 对比起来讲解,是另外一个理解库的角度。