163
社区成员




本实验将使用Python3 实现命令行中的动态进度条,并且能被其它程序调用,为程序执行任务的进度提供直观的展示。
8学时。
该实验在内置Python中完成。
本节将通过实践操作,带领大家使用Python3 实现命令行动态进度条。建议先把程序运行一下看一下效果,再来理解相关代码。
动态进度条同理,即在同一行内连续播放不同的图案。要想在同一行内连续播放不同的图案,就必须知道如何在同一行内输出时覆盖掉之前存在的字符。
先来使用 print() 函数来多次输出不同的字符串:
新建example1.py文件。代码如下:
import time
for i in range(5):
time.sleep(0.3)
print(str(i)*10)
运行 example1.py:
0000000000
1111111111
2222222222
3333333333
4444444444
输出了很多行。但我们要在一行内输出,使用 print() 函数的关键字参数 end 把行末的换行符替换为空字符。
新建example2.py文件。代码如下:
import time
for i in range(5):
time.sleep(0.3)
print(str(i)*10, end='')
运行 example2.py:
00000000001111111111222222222233333333334444444444
这下输出到了一行。但我们很明显的发现,5个字符串是一次性同时输出的。并且每次输出时并未覆盖当前行,而是在行末接着输出。
因为 python 中的标准输入输出默认是使用行缓冲的。而对于行缓冲来说,缓冲区读取到换行符 \n 或回车符 \r 时刷新缓冲区。
我们可以使用 sys.stdout.flush() 函数在每次迭代时刷新缓冲区。
新建example3.py文件。代码如下:
import time
import sys
for i in range(5):
time.sleep(0.3)
print(str(i)*10, end='')
sys.stdout.flush()
运行 example3.py:
00000000001111111111222222222233333333334444444444
现在就不是一次性同时输出了。现在我们解决接着当前行末尾输出的问题。我们只需要使用一个字符:回车符 \r。回车符的作用是回到行首,这时我们再输出字符将会覆盖同一行内已存在的字符。
新建example4.py文件。代码如下:
import time
import sys
for i in range(5):
time.sleep(0.3)
print('\r', end='')
print(str(i)*10, end='')
sys.stdout.flush()
运行 example4.py:
4444444444
最后我们再改进一下,我们直接使用 sys.stdout.write() 代替 print(),并且对输出的字符做了一点变化。
新建example5.py文件。代码如下:
import time
import sys
n = 10
for i in range(n):
time.sleep(0.3)
sys.stdout.write('\r')
sys.stdout.write(str(i)*(n-i))
sys.stdout.flush()
运行 example5.py:
9876543210
这个程序说明了一个问题,覆盖输出的时候只会覆盖掉相同长度的字符。
新建progressbar.py。编写一个类,叫ShowProcess。接下来定义一个全局变量:进度条的长度。
定义50个字符的长度,用max_arrow表示。还要记录进度条当前是第几个,用i表示。
max_steps表示一共有多少个任务。bar_char表示进度条用什么符号表示。
info_done表示进度条到了100%后,输出什么信息。
本实验完整代码如下:
# -*- coding: UTF-8 -*-
import sys
import time
'''
显示处理进度的类
调用该类相关函数即可实现处理进度的显示
'''
class ShowProcess():
# 进度条长度
max_arrow = 50
i = 0
# 初始化函数
def __init__(self, max_steps=100, bar_char = '#', info_done = 'Done'):
self.max_steps = max_steps
self.bar_char = bar_char
self.info_done = info_done
# 显示函数,根据当前的处理进度i显示进度
# 效果为[##################################################] 100.00%
def show_process(self, message = ''):
self.i += 1
num_arrow = int(self.i * self.max_arrow / self.max_steps) #计算显示多少个符号
num_line = self.max_arrow - num_arrow #计算显示多少个'-'
percent = self.i * 100.0 / self.max_steps #计算完成进度,格式为xx.xx%
process_bar = '[' + self.bar_char * num_arrow + '-' * num_line + ']'\
+ ' %.2f' % percent + '% ' + message + '\r' #带输出的字符串,'\r'表示不换行回到最左边
sys.stdout.write(process_bar) #这两句打印字符到终端
sys.stdout.flush()
if self.i >= self.max_steps:
self.close()
def close(self):
print('')
print(self.info_done)
self.i = 0
if __name__=='__main__':
max_steps = 150
process_bar = ShowProcess(max_steps, '#', 'OK')
for i in range(max_steps):
message = 'downloading image_%d.jpg...' %(i+1)
process_bar.show_process(message)
time.sleep(0.5)
本实验了解了命令行动态进度条的原理,并自己编写了一个完整的模块,加深了对输出缓冲区、可变参数列表、面向对象编程的理解。
很不错的内容,干货满满,已支持师傅,期望师傅能输出更多干货,并强烈给师傅文章点赞
另外,如果可以的话,期待师傅能给正在参加年度博客之星评选的我一个五星好评,您的五星好评都是对我的支持与鼓励:https://bbs.csdn.net/topics/611387568
点赞五星好评回馈小福利:抽奖赠书 | 总价值200元,书由君自行挑选(从此页面参与抽奖的同学,只需五星好评后,参与抽奖)