python的进度条有很多第三方库,有些做的比较炫酷,一直都比较好奇进度条的原理,今天研究了一番,如果想要实现一个简单的进度条,还是很容易的。

1. 进度条原理

进度条的难点在于,进度的输出内容始终都在同一行,而平时使用print输出时,都会默认换行,这样就不能实现进度条推进增长的效果了。只要能实现所有输出内容在同一行,后面的输出覆盖前面的输出,进度条也就实现了。而要实现这一点,却是如此的简单,print函数的原型如下
defprint(self,*args,sep=' ',end='\n',file=None):
end默认值是'\n', 表示回车,会换到下一行,把end设置成'\r' ,就不会换到下一行,而是将光标移动到当前行的首位,后面输出的内容,自然就覆盖了前面的内容
importtimeforiinrange(100):print(i,end='\r')time.sleep(0.1)
代码运行起来后,不换行原地从0输出到99。运行这段代码,一定要在终端里,如果是windows系统,请在cmd里运行,或者在pycharm的Terminal里运行,否则是看不到效果的。
掌握了原理,自己就可以实现一个简单的进度条工具了

2. 设计一个简单的进度条

classEasyProcessBar():def__init__(self,name,total):self.name=name# 进度条明后才能self.total=total# 进度总数self.complete_count=0# 已经完成的进度数self.char_count=0# 需要显示的进度字符个数self.char_show_count=0# 已经显示的进度字符个数sz=os.get_terminal_size()# 获取终端长和宽self.char_count=sz.columns-len(name)-15
设计一个EasyProcessBar类
name显示在进度条的最前方既然是显示进度,自然需要知道总进度大小和已经完成的进度数量进度条用#来显示,#的数量不需要和total相同,因为屏幕的宽度是有限的,但total是可以随意设置的os.get_terminal_size()可以获得终端的宽度,宽度减去name的长度,在预留15个字符的宽度用于显示进度百分比,剩余的就是需要显示的#的数量在不同大小的终端里,进度条的大小也不一样,显示会更美观

3. 更新进度

defupdate(self,incr=1):self.complete_count+=incrifself.complete_count>=self.total:self.complete_count=self.totalself.flush()
提供一个update方法,用于更新进度,complete_count大于total是不合理的,最大只能等于total, 更新进度后,要刷新输出

4. 刷新输出

defflush(self):sys.stdout.write(self.process_string)sys.stdout.flush()
我使用了sys.stdout.write方法来输出进度条

5. 生成进度显示的内容

@propertydefprocess_string(self):""" 进度 :return: """ratio=self.complete_count/self.total# 已经完成的百分比char_show_count=int(ratio*self.char_count)# 需要显示的#的数量ifchar_show_count>self.char_show_count:self.char_show_count=char_show_count# 进度条,预留出足够的宽度给百分比process="{process: