第六章 模块
到目前为止我们所有写的代码都在一个文件中,
当我们的程序规模变大时,把所有的功能都放在一个文件中变得不容易维护了
所以我们需要模块,模块和函数一样,是一种封装,让我们把可能会被重复使用的功能封装起来
使用的时候直接拿来用就好了。和函数,类一样,分为定义和使用。
简单来说模块就是一个py文件。
python中的模块可以分为三种
- 标准模块,python语言提供给我们的,可以直接用
- 第三方模块,需要我们下载安装,再使用
- 我们自己定义一个模块,自己使用,也可以让别人用
无论哪一种模块,本质就是一个py文件
6.1 自定义模块和包
自定义一个模块就是自己写一个py文件,我们可以把一类相关的功能放在一个py文件中
# log.py from datetime import datetime def log(msg): print('%s - INFO: %s' % (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), msg)) log('日志消息测试')
#main.py import log log.log("main文件打印消息")
import log
2020-07-23 16:26:12 - INFO: 日志消息测试
2020-07-23 16:26:12 - INFO: main文件打印消息
自己定义一个log.py文件就是一个模块 ,我们在main.py模块中使用import导入,导入后就可以通过. 来引用log模块定义的变量(函数即变量,类也是变量)
使用import在导入模块时,第一次导入会执行模块文件,此后再次导入都不会执行了
如果不想每次使用模块名加 . 来访问模块中的变量,可以使用from语句,指定导入模块中的变量
# main.py from log import log log("使用from语句导入log")
# main.py from log import * log("全部导入")
导入模块或从模块中导入变量时要注意,引入的变量到当前作用域中,会覆盖当前作用域中的同名变量
当然也有可能被当前作用域的同名变量所覆盖,所以要记住,python是从上到下执行的,后面定义的永远会覆盖前面定义的同名变量
# main.py # 当前作用域中的同名变量会被覆盖 log = '我是当前作用域中的变量' from log import log log("我是导入的变量")
# main.py # 被当前作用域中的同名变量覆盖 from log import log log = '我是当前作用域中的变量' log("我是导入的变量")
模块是一个py文件,
包是一个文件夹, 在文件夹中放入__init__.py文件,文件夹就变成了一个包
包其实也是一种模块,只不过一个包里可以包含若干个其它的模块,就是把模块放到包的文件夹里
我们可以通过目录名导入包,包的内容就是__init__.py文件的内容
也可以通过包名.模块名的方式导入包下面的一个模块
# 包 # package/__init__.py from datetime import datetime def package_log(msg): print('%s - PACKAGE: %s' % (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), msg)) package_log('包里的日志消息')
# package/log.py from datetime import datetime def log(msg): print('%s - LOG: %s' % (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), msg)) log('包中模块的日志消息')
# main.py import package import package.log from package import log from package.log import log
注意,无论是导入包,还是导入包下面的模块,都会执行包里的内容
虽然我们导入的时候 可以执行模块或包中的代码,但是一个提供给别人使用的模块,最好只包括定义的语句,不要有过多的执行语句
6.2 导入顺序
目前为止我们的模块和包和我们的代码都放在同一个目录里
如果我们把模块和包放在电脑其它的目录里,导入包和模块的代码放在另一个目录里
导入时就会提示找不到模块和包
导入模块和包是有一个搜索顺序的,按照顺序搜索是否有对应的包和模块,搜索到之后就导入成功,如果搜索不到就报错
导入的顺序是按照一个目录列表来查找的,想查看有哪些目录,我们可以通过以下代码来看
# 导入顺序 import sys from pprint import pprint pprint(sys.path)
['/Users/mac/PycharmProjects/jupyter', '/Users/mac/PycharmProjects/jupyter', '/Users/mac/PycharmProjects/auto-test', '/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python37.zip', '/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7', '/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload', '', '/usr/local/lib/python3.7/site-packages', '/usr/local/lib/python3.7/site-packages/aeosa', '/usr/local/lib/python3.7/site-packages/IPython/extensions', '/Users/mac/.ipython']
我们可以把我们自己定义的模块和包放在上面目录的任何一个位置,这样我们无论在哪里写代码导入都可以导入包和模块
每个人的电脑环境不一样,所以上面的目录列表可能都不相同
但肯定都会有一个site-packages目录,成熟的模块放在这个目录下是最合适的,但要注意不要与产生名字冲突,
很多第三方安装的模块也会放在这个目录 下面
把模块放在目录上面的目录列表是一种方法
另外我们也可以在操作系统中配置环境变量的方式,增加搜索目录
其实也可以直接把目录添加到sys.path列表中,不过这种方法不是特别推荐
系统中配置环境变量PYTHONPATH,把想要添加的搜索目录配置到这个变量中,python搜索模块的路径就会增加这些目录
6.3 模块的属性
python中一切都是对象,很显然,模块也是对象
模块用.来访问他的属性,实际上模块中定义的变量都是模块的属性,包括函数,变量,类
我们学几个特殊的属性
- __doc__
就是模块的帮助文档,模块的帮助文档也是模块中第一个字符串,用来描述模块的功能
可以直接访问,也可以通过help查看
- __file__
模块文件的实际路径,可以直接访问
- __name__
模块文件运行时的名字,如果模块是被导入的,名字是None
如果模块是由解释器运行的,名字是__main__
利用这个,我们可以把模块的调试代码 放在这样一个语句块下
if __name__ == '__main__': print("测试代码在这里")
这样,只有我们写模块的时候 调试的时候,会让解释器直接运行模块 ,就会执行测试代码
如果我们的模块是被其它模块导入使用的,__name__是None就不会执行测试代码
- __all__
__all__我们可以自定义,这是一个列表,其中可以放入我们希望别人使用的模块变量
这样别人在执行
from 模块 import *
这样不会导入其它变量,只会导入__all__列表中的变量
6.4 一些内置模块
6.4.1 sys
| 常用变量 | 含义 |
| argv | 命令行参数 |
| path | 模块导入路径 |
| stdin | 标准输入 |
| stdout | 标准输出 |
| stderr | 标准错误 |
| platform | 操作系统平台 |
6.4.2 os
| 常用变量 | 含义 |
| environ | 环境变量字典 |
| system(command) | 执行操作系统命令 |
| linesep | 换行符 |
| path.split | 分割路径 |
| path.join | 拼接路径 |
| listdir | 列出目录下的文件 |
| remove | 删除文件 |
| mkdir | 创建目录 |
| walk | 遍历目录和文件 |
其中walk值得说一下,walk传入一个路径,返回一个迭代器,我们可以通过一个for循环遍历一个目录下的所有文件
非常实用的一个方法
import os for root, dirs, files in os.walk('/Users/mac/PycharmProjects/python_test'): for file in files: print(os.path.join(root, file))
root是当前文件的目录,dirs是当前文件目录下的目录列表,files是当前文件目录下的文件列表
6.4.3 time和datetime
time模块常用的两个,一个是time.time 返回的是一个时间戳,表示从1970年1月1日0时0分0秒到现在的秒数
time.sleep(sec)可以让程序休眠指定的秒数
datetime模块,主要处理日期和时间
# time datetime import time print(time.time()) time.sleep(1) print(time.time()) from datetime import datetime, timedelta print(datetime.now()) print(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print(datetime.utcnow()) print(datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) #处理日期偏移 print(datetime.now() + timedelta(days=1, seconds=30, minutes=30)) print((datetime.now() - datetime(year=2020, month=7, day=20)).days)
datetime类可以构建一个日期时间对象,timedelta可以构造一个日期时间的间隔
datetime对象之间可以相减,得到日期时间间隔
datetime和日期时间间隔之间可以加减,算出一个新的日期
6.4.4 random
random主要用来处理随机相关的方法
# random import random print('产生1~100之间的随机数', random.randint(1, 100)) print('产生0~1 之间的随机小数', random.random()) print('从列表中随机选择一个元素', random.choice([x for x in range(1,20)])) print('从列表中随机选择三个元素', random.sample([x for x in range(1,20)], 3))
6.4.5 re
re是匹配字符串的一个模块,使用re模块必须先了解正则表达式
正则表达是一种字符串匹配的标准,几乎所有的语言都会支持
python中就是通过 re模块来支持正则表达式
| 模式 | 含义 |
| . | 匹配任意字符,除换行符\r,\n |
| [xyz] | 匹配中括号中的任意一个字符 |
| x|y | 匹配x或y |
| [^xyz] | 匹配不包含中括号中的字符 |
| [a-z] | 匹配小写字符 |
| [A-Z] | 匹配大写字符 |
| [0-9] | 匹配数字 |
| [A-Za-z0-9] | 匹配大小写字母和数字 |
| \d | 匹配任意数字 |
| \D | 匹配任意非数字 |
| \s | 匹配任意不可见字符 |
| ^ | 从行首开始匹配 |
| $ | 人行尾匹配 |
| * | 匹配前面的子表达式0次或任意次 |
| + | 匹配前面的子表达式1次或任意次 |
| ? | 匹配前面的子表达式0次或1次 |
| {n} | 匹配前面的子表达式n次 |
| {n,} | 匹配前面的子表达式至少n次 |
| {n,m} | 匹配前面的子表达式n到m次 |
| \ | 转义 |
6.4.6 pickle存储对象
import pickle l = [1,2,3] f = open('pickle.sav', 'wb') print(pickle.dump(l, f)) f.close() f = open('pickle.sav', 'rb') l = pickle.load(f) print(l)
6.5.7 JSON 序列化
import json employee = { 'name' : '王富贵', 'age' : 18, 'gender': '男', 'address': "深圳市宝安区西乡街道", 'marry' : False, 'hobby' : ['冲浪', '翻船'] } s = json.dumps(employee) print(s) wfg = json.loads(s) print(wfg)
6.5 第三方库
安装第三方库就使用pip命令
pip list pip install pip uninstall pip freeze > requirements.txt pip install -r requirements.txt
6.6 虚拟环境
使用虚拟环境是为了隔离不同项目之间的Python库
创建虚拟环境
Python3 内置了venv模块,首先创建项目目录,进入目录后,执行
python3 -m venv 虚拟名
激活虚拟环境
在开始工作前,先要激活相应的虚拟环境:
windows
scripts/activate
linux
. 虚拟目录/bin/activate
激活后,你的终端提示符会显示虚拟环境的名称。
6.7 编码规范
PEP8

浙公网安备 33010602011771号