Python学习笔记——6.模块
Python 除了在解释器中实时执行,或者单个脚本执行,在复杂程序中也有必要对代码进行组织封装,这就是 Python 的模块文件,与模块相对的,称导入并使用模块的脚本为主文件。
模块例子
一个模块的简单例子如下,由一个 demo.py
文件组成,此时
demo
就是模块名。模块的内容包括其中定义的函数以及可执行的语句等。
1 | # demo.py |
在解释器或者其它脚本中,使用如下语句可以导入模块名
1 | import demo |
然后就可以通过 demo.s
和 demo.fib
等访问模块中的变量和函数。接下来的内容以这个模块为例。
查找模块路径
解释器通过以下路径查找模块:
- 输入脚本的目录(或未指定文件时的当前目录)
- PYTHONPATH 环境变量(目录列表,与 shell 变量 PATH 的语法一样)。
- 依赖于安装的默认值(按照惯例包括一个 site-packages 目录,由 site 模块处理)。
可以使用如下语句打印当前状态的所有的查找路径
1 | import sys |
导入模块语句
导入模块的语法有很多种:
- 只导入模块名称
import demo
,此时对于模块内的标识符,都可以加模块名来访问,例如demo.s
。 - 导入单个标识符
from demo import s
,此时可以直接使用模块中的s
,但是模块名和其它的标识符是无法访问的;类似地,可以导入多个标识符from demo import fib,fib2
。 - 导入所有标识符
from demo import *
,此时可以直接使用模块中的所有标识符。
注意:
- 标识符的导入存在冲突风险,如果不同模块中存在同名的标识符,并且被完全导入,那么后导入的会覆盖先导入的,导致未知错误。因此不建议全部导入,按需导入即可。
- 导入标识符建议使用别名,既可以规避重名冲突,也可以简化标识符,例如对整个模块使用别名
import numpy as np
,或者导入单个标识符时使用别名from numpy import linspace as ls
。 - 在导入所有标识符的语句
from demo import *
中,并不会导入任何下划线开头的标识符,这些被视作私有的,不会自动导入。
可以使用如下命令查看模块中定义的标识符信息
1 | dir(demo) |
注意解释器通常不会重复导入同一个模块,如果修改了模块,建议重启解释器会话。
避免执行模块
在导入模块时,会依次执行模块的所有语句,例如前文中的
demo.py
文件代表的 demo
模块,导入时会自动执行一次赋值语句 s=1
。
通常,我们并不希望导入模块时伴随模块语句的执行,而是仅仅在当前文件作为主文件时才执行,可以使用如下语句完成这样的效果,这里我们参考
C++的习惯,也定义一个 main()
函数
1 | def main(): |
此时,我们通过解释器导入模块,不会显示欢迎信息,但是在命令行直接执行这个脚本,就会显示欢迎信息
1 | $ python demo.py |
模块与包
模块往往对应的是一个单独的 py
文件,与之相对的,包则对应了一个文件夹结构,在其中含有
__init__.py
文件,以及其它的很多 py
文件,这些文件均为一个个单独的模块,称为一个包的子模块。
Python 查找包的时候需要在路径中找到对应包的 __init__.py
文件,将含有这个文件的文件夹视作一个包,例如如下的文件结构
1 | Demo |
对应的是一个名为 Demo 的包,含有 Demo.A.a1
等三个子模块。
在 pip 或者 conda 进行的下载就是以包为单位的。