找回密码
 会员注册
查看: 25|回复: 0

pythontqdm进度条详解

[复制链接]

2万

主题

0

回帖

7万

积分

超级版主

积分
70589
发表于 2024-9-5 16:01:03 | 显示全部楼层 |阅读模式
全文一览一、前言1.1需求来源1.2tqdm快速安装二、代码解析2.1原理简介2.2快速上手2.2.1trange2.2.2其他Iterable2.3定制化显示2.3.1自定义前后缀2.3.2自定义刻度三、实战演示四、运行效率4.1简单加法4.2循环体耗时运算4.3结论五、完整代码一、前言  很多时候,当我们的循环时间较长时,往往想要实时了解当前的进度,以期预知剩余的时间,这让我们对代码的输出有了更强的反馈感。那么,要如何实现呢?1.1需求来源  在循环体里添加print语句或许能够帮上忙,但是这样又会遮蔽有用的信息。很自然地,我们会想到:能不能设计一个类似下载安装进度条那样的东西,来简洁直观地展示进度呢?  这也正是tqdm要实现的目标!1.2tqdm快速安装  由于tqdm不是Python的内置库,在使用前需要先进行安装。我们可以在终端输入以下命令进行安装:#直接安装,略慢#pipinstalltqdm#使用国内(清华)镜像安装,推荐pipinstalltqdm-ihttps://pypi.tuna.tsinghua.edu.cn/simple1234二、代码解析2.1原理简介  在tqdm库中,可以使用tqdm函数对可迭代类型(Iterable)数据进行装饰,返回tqdm.std.tqdm类型的可迭代数据(Iterable)。  可见,装饰前后,二者都是可迭代的,区别在于后者会自动显示进度条!  注意:tqdm.std.tqdm类型只能遍历一次,不能重复使用!2.2快速上手2.2.1trange  trange函数是tqdm中最常用的函数,从其源码中可以看出,trange是tqdm对range类型数据的装饰:deftrange(*args,**kwargs):"""Shortcutfortqdm(range(*args),**kwargs)."""returntqdm(range(*args),**kwargs)123  使用trange可以替代range进行迭代,并显示进度条:importtqdmimporttimeforiintqdm.trange(20):passtime.sleep(0.5)1234562.2.2其他Iterable  除了对range类型,tqdm还能装饰所有常见的可迭代类型:str、tuple、list、set、dict……importtqdma="abcdefg"b=(1,2,3,4,5)c=['a','b','c','d','e','f','g']d={'apple','banana','cherry','date'}e={'a':"Apple",'b':"Banana",'c':"Cherry",'d':"Date"}foriintqdm.tqdm(a):passforiintqdm.tqdm(b):passforiintqdm.tqdm(c):passforiintqdm.tqdm(d):passforiintqdm.tqdm(e):pass12345678910111213  这些Iterable类型都能用于创建进度条:2.3定制化显示  在使用设置函数前,应特意将tqdm对象命名为新的变量(如“progress_bar”),以便调用函数使用。2.3.1自定义前后缀  虽然在2.2中,进度条打印的信息已经非常详细了,但或许这还不能满足我们定制化的需要!当安装一个含多个组件的软件时,如何显示当前安装到哪个组件了呢?  tqdm为此编写了set_description、set_description_str、set_postfix、set_postfix_str等常用函数,在此仅以set_description和set_postfix为例进行演示。importtimeimportrandomfromtqdmimporttqdm#组件中文名称install_components_cn=["运行时库和依赖项","驱动程序","数据库","命令行工具","网络组件","第三方库和框架"]progress_bar=tqdm(install_components_cn)count=0forinfoinprogress_bar:count+=1#前缀progress_bar.set_description(f"正在安装{info}")#后缀progress_bar.set_postfix({"info":f"第{count}项"})#模拟安装时间,设置随机0.5~3.0秒time.sleep(random.uniform(0.5,3.0))1234567891011121314151617  set_description以字符串为参数,为进度条设置前缀;set_postfix以字典为参数,为进度条添加备注信息。set_description_str方法跟set_description方法目的、用法一致;set_postfix_str方法跟set_postfix方法目标一致,但前者传入字符串,后者传入字典。2.3.2自定义刻度  在实际处理工作流stream时,每个文件file的大小并不完全一样,处理后进度条的进展不能视作均等的1/n。那么,如何设置进度条前进的刻度跟文件大小成正相关呢?  这时候,不能直接使用tqdm函数对工作流进行包装,而应该使用total关键字设置总刻度的长度,再用update方法让进度条前进一定的刻度。  注意:此时total关键字的参数必须进行设置,因为其默认为None!否则虽然会显示进度,但不会有进度条!importtimeimportrandomfromtqdmimporttqdm#模拟多个文件,每个文件分别有4、9、3、7段files=[[1,2,3,4],[1,2,3,4,5,6,7,8,9],[1,2,3],[1,2,3,4,5,6,7]]#设置进度条总长度total为files的总段数progress_bar=tqdm(total=sum(len(file)forfileinfiles))count=0forfileinfiles:count+=1#设置前后缀#progress_bar.set_description(f"file:{file}")#progress_bar.set_postfix({"info":f"第{count}项"})time.sleep(random.uniform(0.5,3.0))#进度条向前滚动len(file)刻度progress_bar.update(len(file))progress_bar.close()12345678910111213141516171819  “progress_bar.close()”强烈推荐保留,其作用在于确保进度条能够达到100%并完成显示!  在更新进度条的时候,我们同样还可以设置前后缀!将tqdm的total关键字设置为1,然后将update的参数设置为len(file)/sum(len(file)forfileinfiles),仍能达到相同的效果。三、实战演示  以安装my_app的软件为例,其基本信息如下my_app字典所示:importtimeimportrandomfromtqdmimporttqdmmy_app={"运行时库和依赖项":7,"驱动程序":19,"数据库":4,"命令行工具":3,"网络组件":4,"第三方库和框架":23}defset_up(app):total_size=sum(vfork,vinapp.items())#总大小为100progress_bar=tqdm(app,total=total_size)forcomponentinprogress_bar:size=app[component]progress_bar.set_description(f"正在安装{component}")#progress_bar.set_description_str(f"正在安装{component}")progress_bar.set_postfix({"size":f"{size}MB"})#progress_bar.set_postfix_str(f"size:{size}MB")time.sleep(random.uniform(0.5,3.0))#模拟安装用时progress_bar.update(size)progress_bar.close()if__name__=='__main__':set_up(my_app)123456789101112131415161718192021222324  运行结果如下图所示:四、运行效率引入这样一个实时显示进度的功能,会对我们的代码执行效率有多大影响呢?  对此,我们设计简单的加法运算和耗时的处理两种场景,代入不同大小的n,分析使用tqdm与否的执行时间差。4.1简单加法  编写是否使用tqdm进行求和的两个函数,比较它们在n=100、100000、100000000时各自的运行时间:  importtimefromtqdmimporttrangedefrun_without_tqdm(n):start_time=time.time()res=0foriinrange(n):res+=iprint(time.time()-start_time)defrun_with_tqdm(n):start_time=time.time()res=0foriintrange(n):res+=iprint(time.time()-start_time)if__name__=='__main__':#n=10**2n=10**5#n=10**8run_without_tqdm(n)run_with_tqdm(n)1234567891011121314151617181920212223242526  如下图所示,带tqdm的运行时间是原函数的无数倍、13倍、4倍:4.2循环体耗时运算  编写是否使用tqdm进行等待的两个函数,比较它们在n=100、1000、10000时各自的运行时间:  importtimefromtqdmimporttrangedefrun_without_tqdm(n):start_time=time.time()foriinrange(n):time.sleep(0.001)print(time.time()-start_time)defrun_with_tqdm(n):start_time=time.time()foriintrange(n):time.sleep(0.001)print(time.time()-start_time)if__name__=='__main__':#n=10**2#n=10**3n=10**4run_without_tqdm(n)run_with_tqdm(n)123456789101112131415161718192021222324  如下图,带tqdm的运行时间是原函数的2倍、1倍、1倍:4.3结论  从1.1和4.2的对比结果中,不难看出,使用tqdm会带来一定的额外消耗。但当循环足够多或者循环体耗时较长时,tqdm对效率的影响可以忽略不计!五、完整代码#!/usr/bin/envpython#-*-coding:utf-8-*-#@FileName:progress_bar.py#@Time:2024/1/2214:31#@Author:Carl.Zhang#Function:progress_bar#2.2快速上手——trangeimporttqdmimporttimeforiintqdm.trange(20):passtime.sleep(0.5)##2.2快速上手——其他Iterable:str、tuple、list、set、dict#importtqdm##a="abcdefg"#b=(1,2,3,4,5)#c=['a','b','c','d','e','f','g']#d={'apple','banana','cherry','date'}#e={'a':"Apple",'b':"Banana",'c':"Cherry",'d':"Date"}##foriintqdm.tqdm(a):pass#foriintqdm.tqdm(b):pass#foriintqdm.tqdm(c):pass#foriintqdm.tqdm(d):pass#foriintqdm.tqdm(e):pass##2.3定制化显示——前缀、后缀#importtime#importrandom#fromtqdmimporttqdm###组件中英文名称##install_components_en=["Runtimelibrariesanddependencies","Drivers","Database","Command-linetools",##"Networkingcomponents","Third-partylibrariesandframeworks"]#install_components_cn=["运行时库和依赖项","驱动程序","数据库","命令行工具","网络组件","第三方库和框架"]##progress_bar=tqdm(install_components_cn)#count=0#forcomponentinprogress_bar:#count+=1##前缀##progress_bar.set_description(f"正在安装{component}")##后缀#progress_bar.set_postfix({"info":f"第{count}项"})##模拟安装时间,设置随机0.5~3.0秒#time.sleep(random.uniform(0.5,3.0))###2.3定制化——stream流与update更新#importtime#importrandom#fromtqdmimporttqdm###模拟多个文件,每个文件分别有4、9、3、7段#files=[[1,2,3,4],[1,2,3,4,5,6,7,8,9],[1,2,3],[1,2,3,4,5,6,7]]###设置进度条总长度total为files的总段数#progress_bar=tqdm(total=sum(len(file)forfileinfiles))#count=0#forfileinfiles:#count+=1##设置前后缀#progress_bar.set_description(f"file:{file}")#progress_bar.set_postfix({"info":f"第{count}项"})#time.sleep(random.uniform(0.5,3.0))##进度条向前滚动len(file)/total刻度#progress_bar.update(len(file))#progress_bar.close()##3实战演示#importtime#importrandom#fromtqdmimporttqdm##my_app={"运行时库和依赖项":7,"驱动程序":19,"数据库":4,#"命令行工具":3,"网络组件":4,"第三方库和框架":22}###defset_up(app):#total_size=sum(vfork,vinapp.items())#总大小为100#progress_bar=tqdm(app,total=total_size)#forcomponent,sizeinapp.items():#progress_bar.set_description(f"正在安装{component}")##progress_bar.set_description_str(f"正在安装{component}")##progress_bar.set_postfix({"size":f"{size}MB"})#progress_bar.set_postfix_str(f"size:{size}MB")#time.sleep(random.uniform(0.5,3.0))#模拟安装用时#progress_bar.update(size)#progress_bar.close()###if__name__=='__main__':#set_up(my_app)##4.1运行效率——简单加法#importtime#fromtqdmimporttrange###defrun_without_tqdm(n):#start_time=time.time()#res=0#foriinrange(n):#res+=i#print(time.time()-start_time)###defrun_with_tqdm(n):#start_time=time.time()#res=0#foriintrange(n):#res+=i#print(time.time()-start_time)###if__name__=='__main__':##n=10**2#n=10**5##n=10**8#run_without_tqdm(n)#run_with_tqdm(n)##4.2运行效率——循环体耗时运算#importtime#fromtqdmimporttrange###defrun_without_tqdm(n):#start_time=time.time()#foriinrange(n):#time.sleep(0.001)#print(time.time()-start_time)###defrun_with_tqdm(n):#start_time=time.time()#foriintrange(n):#time.sleep(0.001)#print(time.time()-start_time)###if__name__=='__main__':##n=10**2##n=10**3#n=10**4#run_without_tqdm(n)#run_with_tqdm(n)##封面#importtime#fromtqdmimporttrange##download=trange(15)#foriindownload:#download.set_description("下载中...")###install=trange(20)#foriininstall:#install.set_description("安装中...")###update=trange(35)#foriinupdate:#update.set_description("升级中...")#time.sleep(0.5)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175更多python的使用方法和应用,敬请关注后续更新~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-8 11:45 , Processed in 0.439273 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表