模块 module
01. 什么是模块: 模块是一个包含有一系列变量,函数,类等组成的程序组 模块是一个文件,模块文件通常以.py结尾 作用: 01. 让一些相关的变量,函数,类等有逻辑的组织在一起,使逻辑结构更加清晰 02. 模块中的变量,函数和类可提供给其它模块使用02. 模块的分类:
内置模块(biultins), 在解释器的内部可以直接使用 标准库模块,安装python时已安装且可直接使用 第三方模块(通常为开源), 需要自己安装 用户自己编写的模块(可以作为其它人的第三方模块)03. 模块的导入 import
import 语句 语法: import 模块名1 [as 模块新名1][,模块名2 [as 模块新名2], ....] 示例: import math # 导入数学模块 import sys, os # 导入 sys,os模块 作用: 将某模块整体导入到当前模块中 用法: 模块名.属性名 help(模块名) 查看模块内的变量,函数,类等 模块的导入顺序: 01. 先导入内置模块 02. 再导入第三方模块 03. 最后导入自定义模块 04. from import 语句: 语法: from 模块名 import 模块属性名1 [as 属性新名1], 模块属性名2 [as 属性新名2], ... 作用: 将某模块内的一个或多个属性导入到当前模块的作用域 示例: from math import pi, sqrt from math import factorial as fac from math import sin area = pi * 10 ** 2 # 可以直接使用导入的函数名或变量名05. from import *语句:
语法: from 模块名 import * 作用: 将某模块的所有属性导入到当前模块 示例: from math import * print(sin(pi/2)) print(factorial(10)) 06. 导入模块时的路径索引顺序: 01. 索引程序的运行时路径(当前路径) 02. 搜索 sys.path里提供的路径 03. 搜索内置模块07. 模块化编程的优点:
01. 有利于多人合作开发 02. 使代码更加易于维护 03. 提高代码的复用率 04. 模块化编程有助于解决函数名和变量名冲突(重名)问题,模块内的变量的作用域为模块内全局08. 模块的加载过程:
01. 在模块导入时,模块的所有语句都会执行 02. 如果一个模块已经导入,则再次导入时不会重新执行模块内的语句09. 模块的重新加载:
import imp imp.reload(mymod) # 重新加载已经加载过的mymod模块10. 模块被导入和执行的过程:
01. 先搜索相关路径找模块(.py) 02. 判断是否有此模块对应的.pyc文件,如果没有此文件,则用.py文件 生成相应的.pyc文件再进行加载 03. 如果文件已经存在,则判断.pyc文件和.py文件的修改时间,再决定是否重新生成.pyc文件11. 模块的编译 compile:
编译 解释执行 mymod.py --->> mymod.pyc ---> python312. 模块的文档字符串:
模块内第一行没有赋值给任何变量的字符串为文档字符 此文档字符串可以用help函数查看 说明: 模块的文档字符串被绑定在模块的 __doc__属性上13. __file__属性:
用来绑定模块对应的文件路径名 示例: import mymod2 print(mymod2.__file__)14. 模块的 __name__ 属性:
用来记录模块自身的名字 作用: 01. 记录模块名 02. 用来判断是否为主模块 __name__ 说明: 01. 当此模块作为主模块(也就是第一个运行的模块)运行时,__name__绑定'__main__' 02. 当此模块不是主模块时,模块为文件名去掉'.py'15. 模块的 __all__列表:
模块中的__all__列表是一个用来存放可导出属性的字符串列表 作用: 当用from import * 语句导入模块时,只导入 __all__ 列表内的属性16. 模块的隐藏属性:
模块中以'_' 开头的属性,在from import * 语句导入时,将不会导入,通常称这些属性为隐藏属性 17. 包(模块包) package: 包是将模块以文件夹的组织形式进行分组管理的方法 作用: 1. 将一系列模块进行分类管理,有利于防止命名冲突 2. 可以在需要时加载一个或部分模块而不是全部模块 包示例: mypack/ __init__.py menu.py games/ __init__.py contra.py # 魂斗罗 supermario.py # 超级玛丽 tanks.py # 坦克大战 office/ __init__.py excel.py word.py powerpoint.py 包的导入语法: 如果是直接导入一个包,那么相当于执行了这个包中的__init__文件 并不会帮你把这个包下面的其他包以及py文件自动的导入到内存 如果你希望直接导入包之后,所有的这个包下面的其他包以及py文件都能直接通过包来引用 那么你要自己处理__init__文件 import 包名 [as 包别名] import 包名.模块名 [as 模块新名] import 包名.子包名.模块名 [as 模块新名] from 包名 import 模块名 as 模块新名 from 包名.子包名 import 模块名 [as 模块新名] from 包名.子包名.模块名 import 属性名[as 属性新名] from 包名 import * from 包名.模块名 import * 18. __init__.py 文件: 是常规包内必须存在的文件,__init__.py会在导入包时被自动调用 作用: 01. 编写此包的内容 02. 在内部添加包的文档字符串 03. 在__init__.py 文件内可以加载此包所依懒的其它模块19. 包的__all__列表:
作用: 用来记录此包中有哪儿些子包或模块需要导入 当用from 包 import * 语句导入时,只查 找__all__中的模块或子包 说明: __all__列表只在from xxx import *语句时起作用 说明: 当子包或子包内的模块被导入时,上一层的包也会被先导入 例如: import mypack.games.contra 实质会先导入mypack,再导入games,再导入contra20. 包的相对导入:
包的相对导入是指包内的模块的相互导入 语法: from 相对路径包或模块 import 属性或模块名 或 from 相对路径包或模块 import * 相对路径: 在 from xxxx import 语句中,xxxx 部分可以使用相对路径 . 代表当前目录 .. 代表上一级目录 ... 代表上二级目录 .... 以此类推 注: 1. 相对导入时不能超出包的外部 2. 相的导入要避免循环导入 21. 标准输入输出文件: sys.stdin # 标准输入 sys.stdout # 标准输出 sys.stderr # 标准错误输出 模块名: sys 说明: 每一个python程序启动后都会有以上三个文件已经打开供我们使用 Linux下 Ctrl + D输入文件结束符 示例1: # 此示例示意sys.stdin的用法 import sys print("请输开始输入:")# s = sys.stdin.read(10) # 默认从键盘获取数据
# print(s) # s2 = sys.stdin.read(10) # print(s2)s = sys.stdin.read()
print("您刚才输入的是:", s) 示例2: # 此程序示意标准输出sys.stdout 和标准错误输出 sys.stderr import sys # 导入sys模块sys.stdout.write("hello world\n")
# 等同于 print('hello world', end='\n')# 以下程序会出错
# sys.stdout.close() # print("程序结束!") sys.stderr.write("我的出现是个错误!\n") Python常用模块: 01. time 时间模块: import time# time()取时间戳-->做计算
print(time.time()) # 1553274079.3324106秒-->1970年凌晨到现在的时间秒# localtime结构化时间-->当地时间
t = time.localtime() # 默认参数time.time() print(t) print(t.tm_year) # 打印年# gmtime结构化时间-->UTC世界标准时间, 比中国时间慢8小时
print(time.gmtime()) # 格林时间# mktime结构化时间转换成时间戳
print(time.mktime(t))# strftime结构化时间转换成字符串时间
print(time.strftime("%Y-%m-%d %X", t)) # Y年 m月 d日 X时分秒 t结构化时间# strptime将字符串时间转换成结构化时间
print(time.strptime("2019:03:23:01:26:11", "%Y:%m:%d:%X"))# asctime()将结构化时间转换成固定的字符串表达方式-->默认参数取当前结构化时间
print(time.asctime()) # 周月日时分秒年# ctime()将时间戳时间转换成固定的字符串表达方式-->默认参数取当前时间戳
print(time.ctime()) # 周月日时分秒年# sleep()线程推迟指定时间运行,单位秒
time.sleep(1) # 睡一秒 # 日常时间显示 import datetime print(datetime.datetime.now()) # 2019-03-23 01:54:52.165174 02. random 随机模块: # random随机模块 import random ret = random.random() # (0,1)随机取浮点数 ret = random.randint(1, 3) # [1, 3]随机取整数 ret = random.randrange(1, 3) # [1, 3)随机取整数 ret = random.choice([11, 22, 33]) # [可迭代序列]取随机值 ret = random.sample([11, 22, 33], 2) # [可迭代序列]取随机2个值 ret = random.uniform(1,3) # (1, 3)取指定范围的浮点数 print(ret) item = [1, 2, 3, 4, 5] random.shuffle(item) # 随机打乱列表的序列 print(item) 03. os 模块: # os模块是与操作系统交互的一个模块 import os# getcwd获取当前工作目录,即当前python脚本工作目录路径
print(os.getcwd()) # G:\PycharmProjects\11_模块\lnh_massage# chdir改变当前脚本的工作目录,相当于shell下的cd命令
os.chdir("test1") print(os.getcwd()) # G:\PycharmProjects\11_模块\lnh_massage\test1 os.chdir("..") print(os.getcwd()) # G:\PycharmProjects\11_模块\lnh_massage# curdir返回当前目录
print(os.curdir) # .# pardir获取当前父目录字符串名
print(os.pardir) # ..# makedirs 可递归创建文件夹
os.makedirs("makir1/mkdir2")# removedirs 文件夹为空则可递归删除文件夹,知道非空为止
os.removedirs("makir1/mkdir2")# mkdir 生成前单级目录
os.mkdir("test2")# rmdir 删除单级空目录,目录不为空则无法删除
os.rmdir("test2")# listdir 列出指定文件下的所有文件和子目录,包含影藏文件,返回一个列表
print(os.listdir("test1"))# remove 删除一个文件
os.remove("test1/111")# rename 重命名文件/目录
os.rename("test1", "test1")# stat 获取文件/目录信息
print(os.stat(r"G:\PycharmProjects\11_模块\lnh_massage"))# sep 查看操作系统的特定路径分割符
print(os.sep) # Windows为:“\”,Linux为:“/”# linesep 查看当前平台使用的终止符
print("终止符", os.linesep) # win下“\r\n”,linux下“\n”# pathsep 查看用于分割文件路径的字符串
print("分隔文件", os.pathsep) # win下“;”,linux下“:”# name 以字符串指示查看当前使用平台
print("使用平台", os.name) # win下“nt”,linux下“posix”# system 运行shell命令,直接显示
os.system("ping 127.0.0.1")# environ 获取系统环境变量
print(os.environ)# path.abspath() 返回规范化的path绝对路径
print(os.path.abspath(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # G:\PycharmProjects\11_模块\lnh_massage\test1 # path.split 将path分割成目录和文件名,返回元组 print(os.path.split(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # ('G:\\PycharmProjects\\11_模块\\lnh_massage', 'test1')# path.dirname 返回path.abspath()的第一个元素,目录
print(os.path.dirname(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # G:\PycharmProjects\11_模块\lnh_massage# basename 返回path.abspath()的第二个元素,文件名
print(os.path.basename(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # test1# path.exists 判断path是否存在,返回布尔值
print(os.path.exists(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # True# path.isabs 判断path是否是绝对路径,返回布尔值
print(os.path.isabs(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # True# path.isfile 判断path是否是一个存在的文件,返回布尔值
print(os.path.isfile(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # False# path.isdir 判断path是否是一个存在的目录
print(os.path.isdir(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # True# path.join 路径拼接,会自动去找当前操作系统的路径分割符拼接
a = r"G:\PycharmProjects" b = r"11_模块\lnh_massage\test1" print(os.path.join(a, b)) # G:\PycharmProjects\11_模块\lnh_massage\test1# path.getatime 返回path所指向的文件或目录最后一次存取时间
print(os.path.getatime(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # 1553962262.1905563# path.getmtime 返回path所指向的文件或目录最后一次修改时间
print(os.path.getmtime(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # 1553962262.1905563 # path.getsize 返回path所指向的文件的大小, 单位为字节 print(os.path.getsize(r"G:\PycharmProjects\11_模块\lnh_massage\test1")) # 397 模块导入添加path路径示例: import sys import os # lst = __file__.split('/') # # base_path = '/'.join(lst[:-2]) base_path = os.path.dirname(os.path.dirname(__file__)) sys.path.append(base_path) from core import main 04. sys 模块: # sys模块与python解释器交互的一个模块 import sys, time# eixt(0) 退出程序
print(sys.exit(0))# argv 命令行参数,返回列表,第一个元素是程序本身路径
print(sys.argv) # ['D:\\ProgramData\\Anaconda3\\Scripts\\ipython']# version 获取python解释器版本信息
print(sys.version) # 3.7.1 (default, Dec 10 2018, 22:54:23) [MSC v.1915 64 bit (AMD64)]# path 返回模块的搜索路径
print(sys.path)# platform 返回操作系统平台名称
print(sys.platform) # win32# 进度条
for i in range(100): sys.stdout.write("#") # 向屏幕显示相应的内容 time.sleep(0.1) sys.stdout.flush() # 刷新缓存 05. json&pickle 模块: import json # 序列化模块,将数据转换成json的字符串dic = {"name": "coco"}
data = json.dumps(dic) # 转换成所有语言都支持的json的字符串 print(data) print(type(data)) f = open("test2", "w") # data = json.dump(dic, f) # 直接转化写入文件 f.write(data) f.close()f_read = open("test2", "r")
data1 = json.loads(f_read.read()) # 将json处理的字符串还原原来的数据类型 # data1 = json.load(f) # 直接读取还原 print(data1) print(type(data1)) f_read.close()# pickle 序列化模块,将数据转换成字节,还支持函数和类的转换
import pickle dic1 = {"name": "coco"} data2 = pickle.dumps(dic1) # 转换成所有语言都支持的pickle的bytes print(data2) print(type(data2)) f1 = open("test3", "wb") # data = pickle.dump(dic1, f) # 直接转化写入文件 f1.write(data2) f1.close()f1_read = open("test3", "rb")
data3 = pickle.loads(f1_read.read()) # 将pickle处理的bytes还原原来的数据类型 # data3 = pickle.load(f) # 直接读取还原 print(data3) print(type(data3)) f_read.close() 06. shelve 模块: 常用方式: 文件改动的比较少, 读文件的操作比较多 且大部分读取都需要基于某个key获得某个value import shelvef = shelve.open(r"shelve.txt") # 生成一个空文本
f["stu1_info"] = {"name": "coco", "age": "26"} # 将字典放入文本 f["stu2_info"] = {"name": "angels", "age": "18"} f.close() print(f.get("stu1_info")["age"]) # 26 07. xml 模块: import xml.etree.ElementTree as ET # as 取别名tree = ET.parse("xml_lesson") # parse解析xml,返回一个解析对象
root = tree.getroot() # getroot 取根节点 print(root.tag) # tag 拿到根节点的标签名# 遍历xml文档
for child in root: print(child.tag, child.attrib) # tag标签名,attrib标签属性 for i in child: print(i.tag, i.text) # text标签的内容# 只遍历year节点
for node in root.iter("year"): # iter指定拿root根下的某个节点 print(node.tag, node.text)# 修改
for node in root.iter("year"): new_year = int(node.text) + 1 # 修改year标签内容 node.text = str(new_year) # 重新赋值修改内容 node.set("updated", "yes") # 为year标签添加属性 tree.write("xml_lesson") # 把修改后内容从新写一个文件,同名则覆盖原文件# 删除
for country in root.findall("country"): # findall 找root的所有country标签 rank = int(country.find("rank").text) # find 找country下的rank标签 if rank >= 50: root.remove(country) tree.write("xml_output") # 把修改后内容从新写一个文件,同名则覆盖原文件 # 创建一个xml new_xml = ET.Element("namelist") # Element 创建根节点 name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"}) age = ET.SubElement(name, "age", attrib={"checked": "no"}) sex = ET.SubElement(name, "sex") sex.text = "26"et = ET.ElementTree(new_xml) # 生成文档对象
et.write("xml_text.xml", encoding="utf-8", xml_declaration=True) # 写出到文档 ET.dump(new_xml) # 打印生成格式 08. re 正则模块: import re# 普通字符 findall("匹配规则", "匹配内容")
# findall会优先显示分组中的内容,要想取消分组优先,(?:正则表达式) print(re.findall("coco", "my name is coco hao are you"))# 元字符:. ^ $ * + ? {} [] | () \
# .通配符,除了\n以外的所有字符都可以用.代替,一个点代指1个字符 print(re.findall("m.....e", "my name is coco hao are you"))# ^只能在字符串开头匹配内容
print(re.findall("^m..n", "my name is coco hao are you"))# $只能在字符串结尾匹配内容
print(re.findall("e...u$", "my name is coco hao are you"))# *匹配0-无穷次的内容
print(re.findall("^d*", "dddddefghddd"))# +匹配1-无穷次的内容
print(re.findall("d+", "dddddefghddd"))# ?匹配0次或者1次的内容
print(re.findall("ghf?", "dddddefghddd"))# {}匹配指定次数的内容
print(re.findall("ghd{0,2}", "dddddefghddd"))# []字符集,字符集里的功能符号只有- ^ \
print(re.findall("x[yz]", "xyaaaxz")) print(re.findall("x[a-z]", "xyappxcappxzapp")) # -范围 print(re.findall("x[^a-z]", "xyappxcappxzappx1")) # ^非 print(re.findall("\([^()]*\)", "1+(2*3+5-(2-(5-4)))")) # \转义# \转义元字符
print(re.findall("5\*3\+2", "5*3+2-10")) # \d:匹配任意十进制数,相当于[0-9] print(re.findall("\d+", "1+(2*3+5-(2-(5-4)))")) # \D:匹配任意非十进制数,相当于[^0-9] print(re.findall("\D+", "1+(2*3+5-(2-(5-4)))")) # \s:匹配任何空白字符,相当于[\t\r\f\v] print(re.findall("\s+", "hello world")) # \S:匹配任何非空白字符,相当于[^\t\r\f\v] print(re.findall("\S+", "hello world")) # \w:匹配任何字母数字,相当于[a-zA-z0-9_] print(re.findall("\w+", "hello world 12345")) # \W:匹配任何非字母数字,相当于[^a-zA-z0-9_] print(re.findall("\W+", "hello world 12345")) # \b:匹配一个特殊字符边界,如空格 & # 等 print(re.findall(r"lo\b", "hello hello#hello&")) # r 后面的内容pythonIDE不解释,交给re解释# |管道符-->或
print(re.findall("ac|b", "123ac566546b"))# ()分组
print(re.findall("(abc)+", "abc11abc22abc33")) # search 如果search中有分组的话,通过group(n)就能够拿到group中的匹配的内容 # (?P<name>正则表达式) 表示给分组起名字 ret = re.search("(?P<name>[a-z]+)(?P<age>\d+)","coco26alex30").group("name") print(ret) # coco# mach查找方法
ret = re.match("a", "abc").group() # 通search,不同在以字符串开始出进行匹配 print(ret) # a# split分割方法, 遇到分组 会保留分组内被切掉的内容
ret = re.split("[ab]", "abcd") # 先按a分割得""和"bcd"再对""和"bcd"按b分割 print(ret) # ['', '', 'cd']# sub替换方法
ret = re.sub("\d+", "A", "d22d33sd44", 2) print(ret) # dAdAsd44# subn替换方法
ret = re.subn("\d+", "A", "d22d33sd44") print(ret) # ('dAdAsdA', 3)# compile编译方法
# 节省时间:只有在多次使用某一个相同的正则表达式的时候,这个compile才会帮助我们提高程序的效率 com = re.compile("\d+") ret = com.findall("avc11sss22ssgg33") print(ret) # ['11', '22', '33']# finditer方法处理后返回迭代器, 空间效率
ret = re.finditer("\d+", "asd22sa33") print(ret) # <callable_iterator object at 0x0000000003548BE0> print(next(ret).group()) # 22 print(next(ret).group()) # 33# ?:去优先级
ret= re.findall("www\.(baidu|163)\.com", "aawww.baidu.combb") print(ret) # ['baidu'] ret= re.findall("www\.(?:baidu|163)\.com", "aawww.baidu.combb") print(ret) # ['www.baidu.com'] 09. logging 日志模块: import logging# basicConfig定义日志
logging.basicConfig( level=logging.DEBUG, # 设置显示日志级别 filename="logger.log", # 设置追加写出日志 filemode="w", # 覆盖写入 format="%(asctime)s %(filename)s [line:%(lineno)d] %(message)s" # 设置写出格式 )# 日志的五个级别
logging.debug("debug message") # 调试模式 logging.info("info message") # 基础信息 logging.warning("warning massage") # 警告 logging.error("error massage") # 错误 logging.critical("critical massage") # 严重错误# getLogger创建对象定义日志
def logget(): logget = logging.getLogger() # 创建一个logger对象 fh = logging.FileHandler("logger1.log") # 创建一个文件管理操作符,向文件发送日志 ch = logging.StreamHandler() # 创建一个屏幕管理操作符,向屏幕发送日志fm = logging.Formatter("%(asctime)s %(message)s") # 创建一个日志输出的格式,定义日志格式
fh.setFormatter(fm) # 文件管理操作符 绑定一个 格式 ch.setFormatter(fm) # 屏幕管理操作符 绑定一个 格式logget.addHandler(fh) # logger对象 绑定 文件管理操作符
logget.addHandler(ch) # logger对象 绑定 屏幕管理操作符 logget.setLevel("DEBUG") # 设置日志显示级别 return logget logget = logget() logget.debug("debug message") logget.info("info message") logget.warning("warning massage") logget.error("error massage") logget.critical("critical massage") 10. configparser 配置文件模块: import configparserconfig = configparser.ConfigParser()
config["DEFAULT"] = {
"Sever": "45", "Compression": "yes", "CompressionLevel": "9" }config["bt.org"] = {}
config["bt.org"]["User"] = "coco"config["sever.com"] = {}
top = config["sever.com"] top["Host Ip"] = "127.0.0.1" top["Host Port"] = "8080"with open("example.ini", "w") as configfile:
config.write(configfile)# 查配置文件
config.read("example.ini") print(config.sections()) # 读除默认块以外的块名['bt.org', 'sever.com'] print(config["bt.org"]["user"]) # coco for key in config: print(key)print(config.options("bt.org")) # ['user', 'sever', 'compression', 'compressionlevel']
print(config.items("bt.org")) # [('sever', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('user', 'coco')] print(config.get("bt.org", "user")) # coco# 添加,修改,删除
config.add_section("yun") # 添加块 config.set("yun", "k1", "11") # 添加键值对,同名覆盖即修改 config.remove_option("sever.com", "host port") # 删除块下的某个键值对 config.remove_section("sever.com") # 删除块及块里面的的所有键值对config.write(open("i.cfg"), "w")
11. hashlib 算法摘要模块: import hashlib# md5
# md5是一个算法,32位的字符串,每个字符都是一个十六进制 # md5算法 效率快 算法相对简单 obj = hashlib.md5("ssasdf".encode(encoding="utf8")) # 自定义加盐 obj.update("coco".encode(encoding="utf8")) # 原生md5加密 print(obj.hexdigest()) # 516dacada2fea0112265e3a474dee5fe# sha256
obj = hashlib.sha256("ssasdf".encode(encoding="utf8")) # 自定义加盐 obj.update("coco".encode(encoding="utf8")) # 原生md5加密 print(obj.hexdigest()) # 577cce053410c4bf7ccee892b3d92c55f20c56b773276a326777a4535a021909 # sha1也是一个算法,40位的字符串,每个字符都是一个十六进制 # 算法相对复杂 计算速度也慢 md5_obj = hashlib.sha1() md5_obj.update(s1.encode('utf-8')) res = md5_obj.hexdigest() print(res,len(res),type(res)) # 动态加盐 username = input('username : ') passwd = input('password : ') md5obj = hashlib.md5(username.encode('utf-8')) md5obj.update(passwd.encode('utf-8')) print(md5obj.hexdigest()) # ee838c58e5bb3c9e687065edd0ec454f # 文件的一致性校验 md5_obj = hashlib.md5() with open('5.序列化模块_shelve.py','rb') as f: md5_obj.update(f.read()) ret1 = md5_obj.hexdigest()md5_obj = hashlib.md5()
with open('5.序列化模块_shelve.py.bak','rb') as f: md5_obj.update(f.read()) ret2 = md5_obj.hexdigest() print(ret1,ret2) # 大文件的已执行校验 md5_obj = hashlib.md5() with open('5.序列化模块_shelve.py.bak','rb') as f: md5_obj.update(f.read()) # 循环 循环的读取文件内容 # 循环的来update print(md5_obj.hexdigest())