相信很多人在寫一些簡單的Python腳本的時候都希望能夠在程序運行的過程中實現進度條的功能以便查看程序運行的速度或者進度。
我之前一直想實現這樣一個東西,也查看了許多博客但是都找不到一個完美的解決方案(當然,使用progressBar這個庫是個選擇,但很多時候我們需要一些定制功能的時候就需要考慮自己實現,其實也挺簡單的,不想看廢話的可以直接跳到最後)
進度條最主要的問題就是所有字符全部在同一行,而且可以修改。
然而當執行print語句的時候,python會在打印完這個語句的同時在結尾加上'\n',也就是換行,這就導致在控制台下一旦被print之後就無法再修改了。所以我們現在的輸出就不能再使用print來完成了。
我們要使用的是來自sys庫的sys.stdout.write()函數,這個函數會在控制台輸出這個字符串的同時不加上任何結尾,這就意味著這個輸出還沒有完全結束。通過sys.stdout.flush()函數可以把輸出暫時打印在控制台中(造成print的假象,我們姑且先叫這個假輸出)。那麼如果我們使用'\r'這個轉義字符(回到行首),一切看起來是不是就合理很多了呢?
也就是說:打印字符串的時候,沒有加上'\n',同時讓光標回到行首,再把當前緩沖區顯示出來,也就好象是print了一樣,但是這時候光標還在原來的位置。
舉個例子:
import sys, time
for i in range(5):
sys.stdout.write('{0}/5\r'.format(i + 1))
sys.stdout.flush()
time.sleep(1)
在終端下執行這段代碼就會得到簡單的進度條效果。
--------------------------------------------------------------------------------
接下來還需要解決兩個問題:
一:清空緩沖區
有些聰明的讀者可能發現,當新的字符串比之前短的時候會出現問題,比如下面這段代碼:
import sys, time
for i in range(5):
sys.stdout.write(str(i) * (5 - i) + '\r')
sys.stdout.flush()
time.sleep(1)
運行後發現結果跟我們希望的不太一樣。
其實是因為已經被flush出去的字符並不會主動清空,所以只有新寫入的被修改了。針對這點我目前的解決方案是先輸出一波空格把之前的字符串沖掉然後重新寫:
import sys, time
for i in range(5):
sys.stdout.write(' ' * 10 + '\r')
sys.stdout.flush()
sys.stdout.write(str(i) * (5 - i) + '\r')
sys.stdout.flush()
time.sleep(1)
二:固定底邊輸出
有時候我們希望在進度條加載的同時還有一些其他的輸出。
我們不妨在刷新掉上一次輸出之後輸出所需輸出的字符串,然後在假輸出進度條。
采用如下代碼:
import sys, time
for i in range(5):
sys.stdout.write(' ' * 10 + '\r')
sys.stdout.flush()
print i
sys.stdout.write(str(i) * (5 - i) + '\r')
sys.stdout.flush()
time.sleep(1)
就可以完成所需任務了。
--------------------------------------------------------------------------------
怎麼樣,其實原理還是挺簡單的吧?
這裡給出一個自己實現的類用來打印進度條:
# -*- coding:utf-8 -*-
# Copyright: Lustralisk
# Author: Cedric Liu
# Date: 2015-11-08
import sys, time
class ProgressBar:
def __init__(self, count = 0, total = 0, width = 50):
self.count = count
self.total = total
self.width = width
def move(self):
self.count += 1
def log(self, s):
sys.stdout.write(' ' * (self.width + 9) + '\r')
sys.stdout.flush()
print s
progress = self.width * self.count / self.total
sys.stdout.write('{0:3}/{1:3}: '.format(self.count, self.total))
sys.stdout.write('#' * progress + '-' * (self.width - progress) + '\r')
if progress == self.width:
sys.stdout.write('\n')
sys.stdout.flush()
bar = ProgressBar(total = 10)
for i in range(10):
bar.move()
bar.log('We have arrived at: ' + str(i + 1))
time.sleep(1)
效果如下:
--------------------------------------------------------------------------------
這樣就可以方便的在一些任務中查看程序運行的進度了,比如爬蟲、機器學習等並不知道要花多少時間等工作也都可以有形象的時間把握了。
如果有什麼其他好的建議歡迎共同討論~
博客中全部資源均出自開源資源或者公開論文。 歡迎共同探討交流。 聯系方式:[email protected]
下面關於Python的文章您也可能喜歡,不妨看看:
Linux下Python的安裝以及注意事項 http://www.linuxidc.com/Linux/2015-11/124861.htm
Ubuntu 14.04 下安裝使用Python rq模塊 http://www.linuxidc.com/Linux/2015-08/122441.htm
無需操作系統直接運行 Python 代碼 http://www.linuxidc.com/Linux/2015-05/117357.htm
CentOS上源碼安裝Python3.4 http://www.linuxidc.com/Linux/2015-01/111870.htm
《Python核心編程 第二版》.(Wesley J. Chun ).[高清PDF中文版] http://www.linuxidc.com/Linux/2013-06/85425.htm
《Python開發技術詳解》.( 周偉,宗傑).[高清PDF掃描版+隨書視頻+代碼] http://www.linuxidc.com/Linux/2013-11/92693.htm
Python腳本獲取Linux系統信息 http://www.linuxidc.com/Linux/2013-08/88531.htm
在Ubuntu下用Python搭建桌面算法交易研究環境 http://www.linuxidc.com/Linux/2013-11/92534.htm
Python 語言的發展簡史 http://www.linuxidc.com/Linux/2014-09/107206.htm
Python 的詳細介紹:請點這裡
Python 的下載地址:請點這裡