使用python时,常常会涉及到库的调用,这就需要掌握模块的基本知识。本文分为如下几个部分
- 概念说明
- 模块的简单调用
- 包的导入
- 特殊的
__init__.py
文件 - 导入模块的搜索路径
__all__
- 绝对引用与相对引用
- import运行本质
if __name__ == '__main__'
概念说明
这里厘清python中模块、库、包之间的概念差异
- 模块(module)其实就是py文件,里面定义了一些函数、类、变量等
- 包(package)是多个模块的聚合体形成的文件夹,里面可以是多个py文件,也可以嵌套文件夹
- 库是参考其他编程语言的说法,是指完成一定功能的代码集合,在python中的形式就是模块和包
模块的简单调用
比如我们有一个trymodule
的文件夹,里面有一个first.py
文件,文件中的内容如下
在trymodule
的文件夹下打开命令行窗口(按住shift单击鼠标右键,选择“在此处打开命令窗口”),输入python
进入命令行交互模式
所以说first.py文件就是一个模块,可以用import
导入,里面变量都要用first.
前缀来引用,如果想不使用这个前缀可以这样
其他用法如下
很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:609616831
包的导入
在trymodule文件夹中新建folder1
文件夹,我们想让folder1
文件夹成为一个包。文件夹里新建abcd.py
文件,文件中内容如下
此时在folder1
文件夹中新建一个__init__.py
文件,否则程序会将这个文件夹当成普通文件夹来处理而不是一个包。这个__init__.py
文件中可以什么都不填。
此时文件结构如下
我们还是在trymodule
文件夹下打开命令行,进入python交互模式
我们来看一下下面几种导入方式
注意:
- 只是导入包不能随便使用其中的模块,要导入到具体模块或者变量的层次
- 文件夹与文件之间可以用
.
也可以用from import
格式,而文件与里面的变量之间只能用from import
格式,即不能import folder1.abcd.b
特殊的__init__.py
文件
__init__.py
文件其实是一个特殊的文件,它相当于名为folder1模块,即如果使用import folder1
则可以调用在__init__.py
文件文件中定义的变量。
将__init__.py
文件编写如下
在trymodule文件夹下打开命令行,进入python交互模式
对比之前的from folder1.abcd import b
,使用__init__.py
文件可以将常用的一些变量导入以方便调用。
另外需要注意两点
__init__.py
文件编写时,如果要导入其他模块中的变量,即使__init__.py
文件和abcd.py
文件在同一个文件夹下,也不能from abcd import b
,要从abcd文件从哪里来的开始写,即从包的名称开始。- folder1文件夹里的嵌套文件夹内不需要新建
__init__.py
文件即可像模块一样调用,但是一般还是要新建这个文件,可以方便地导入常用变量。
导入模块的搜索路径
用import hello
时,python会搜寻hello.py
文件,搜索顺序如下
- 首先搜寻内置模块是否有
hello
(所以我们定义的模块名不要和内置模块相同) - 如果内置模块没有,则看下面这些目录里有没有
其中第一个''
表示当前的工作路径,我们可以看出安装的第三方包所在路径('C:\Program Files\Anaconda3\lib\site-packages'
)也在这个列表之中,所以无论工作路径在哪里,都能搜寻到这些包。
如果想添加搜索路径,可以参考这篇文章
__all__
首先要明确,import *
的方式无法导入以下划线开头的变量名
__init__.py
文件内容更改如下
python交互模式下
而如果指定导入是可以的
如果定义了__all__
,则import *
就可以导入下划线开头的变量
__init__.py
文件内容更改如下
python交互模式下
可见import *
只会导入__all__
中指定的变量,无论是否以下划线开头。这样限制可以防止import *
命令导入太多变量污染命名空间,过滤掉一些中间变量如b
绝对引用与相对引用
python中的import
分为绝对引用和相对引用两种。它们之间的差异在于,引用模块时 定位被引用模块位置 的方式不同
- 绝对引用是明确指定最高级文件(夹),文件之间用
.
连接,依次下来达到待引用模块。我们上面的所有用法都属于绝对引用。 - 而相对引用是 指定待引用模块与当前文件的相对位置,
.
表示上一级文件
在这样的文件结构下
编写__init__.py
文件,其中要引用abcd.py
文件中的变量
- 绝对引用是
from folder1.abcd import b
- 相对引用是
from .abcd import b
相对引用中,.
是指父文件(也有from . import xxx
的用法),.xxx
是指同一层文件,..xxx
则是与父文件夹同级的xxx
文件(多一个.
表示多往上一层)
一般用哪个呢?
python3之后官方推荐用绝对引用的方式,只有当模块中文件关系非常复杂时相对引用才会有优势。
import运行本质
使用import
语句,要明确两件事
(1)执行导入模块命令时,会首先检查待导入的模块是否在当前已有模块之中,如果有则跳过import
。因此模块之间相互引用不会导致无限循环。
查看当前已导入模块使用下面方法
得到结果是一个字典,键是模块名,值是文件所在路径
(2)import
语句与文件执行
在这样的文件结构下
folder1是一个package,abcd是一个module
import folder1
只是导入package,相当于执行__init__.py
文件from folder import abcd
则执行了__init__.py
文件文件与abcd.py
文件from folder1.abcd import b
其实也执行了__init__.py
文件文件与abcd.py
文件
(要知道执行了什么,可以在这些文件之中添加print
语句,看是否打印出结果)
知道这个执行原理,可以更好理解前面得到的一些结论
- 首先是在
__init__.py
文件中什么都没有的情况下,import folder1
无法调用abcd
模块中的变量,是因为相当与运行了一个空文件,没有将整个包导入工作空间 abcd
模块中定义了print
语句后,import
两次,只有第一次会print
出值,说明第二次检查出模块已在导入之列,忽略了这条import
命令
更多运行细节可以参考这篇文章
if __name__ == '__main__'
我们经常会在别人的代码中发现if __name__ == '__main__'
,为了理解它的作用,我们来看下面的例子
在folder1文件夹下新建new.py文件,里面内容为
在folder1文件夹下打开命令行,输入
返回结果是__main__
在trymodule文件夹下打开命令行,进入python交互模式
上面测试结果说明直接运行文件和import
文件是有差异的,差异在于二者的__name__
变量不同。__name__
变量是一个特殊的变量,每个py文件运行时都会对应一个__name__
变量,即使在交互模式下也可以查看这个变量值。
所以if __name__ == '__main__'
的作用就很好理解了,即import
时不执行下面的代码,只有在直接执行这个文件时才运行之后的代码。这算是一种约定俗成的写法,如果不怕文件被import
,可以不用这个。