2010-07-04 230 views
250

有沒有一種很好的方法來執行以下操作?控制檯中的文本進度條

我寫了一個簡單的控制檯應用程序,使用ftplib從FTP服務器上傳和下載文件。

每次下載一些數據塊時,我想更新文本進度條,即使它只是一個數字。

但我不想擦除已打印到控制檯的所有文本。 (做一個「清除」,然後打印更新的百分比。)

+2

你也可以只使用一個圖形用戶界面(如果你開始做任何事情,這將節省你到底有多麻煩前進在應用程序)它不是1960年了) – 2010-07-04 00:55:34

+0

嗯,看起來像這個問題的重複問昨天:http://stackoverflow.com/questions/3160699/python-progress-bar/3162864 所以,你應該使用魚http://pypi.python.org/pypi/fish/ – Etienne 2010-07-04 02:33:35

+5

「只使用GUI」誤解了GUI在某些情況下很棒(快速學習曲線,專門的探索性或交互式或一次性活動),而命令行工具對其他人來說非常適用(專家用戶,即時編寫臨時應用程序以多次執行精心定義的操作。) – 2016-05-11 02:54:28

回答

176

這裏有許多下面的答案我經常使用的集合體。

# Print iterations progress 
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'): 
    """ 
    Call in a loop to create terminal progress bar 
    @params: 
     iteration - Required : current iteration (Int) 
     total  - Required : total iterations (Int) 
     prefix  - Optional : prefix string (Str) 
     suffix  - Optional : suffix string (Str) 
     decimals - Optional : positive number of decimals in percent complete (Int) 
     length  - Optional : character length of bar (Int) 
     fill  - Optional : bar fill character (Str) 
    """ 
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration/float(total))) 
    filledLength = int(length * iteration // total) 
    bar = fill * filledLength + '-' * (length - filledLength) 
    print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r') 
    # Print New Line on Complete 
    if iteration == total: 
     print() 

# 
# Sample Usage 
# 

from time import sleep 

# A List of Items 
items = list(range(0, 57)) 
l = len(items) 

# Initial call to print 0% progress 
printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50) 
for i, item in enumerate(items): 
    # Do stuff... 
    sleep(0.1) 
    # Update Progress Bar 
    printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50) 

# Sample Output 
Progress: |█████████████████████████████████████████████-----| 90.0% Complete 
+10

這段代碼很棒!我遇到了一些小問題,所以我做了一些小修改(PEP-8,非ASCII字符的默認編碼),並將它們扔在這裏: https://gist.github.com/aubricus/f91fb55dc6ba5557fbab06119420dd6a – Aubricus 2016-11-03 18:01:09

+1

Worth注意UTF-8聲明沒有必要,除非你使用Python 2 @Aubricus – Greenstick 2016-11-04 18:35:33

+1

是的。好點子!我用筆記更新了要點。 – Aubricus 2016-11-07 18:28:48

97

寫一個\r到控制檯。這是一個"carriage return",它導致它後面的所有文本在行首開始回顯。喜歡的東西:

def update_progress(progress): 
    print '\r[{0}] {1}%'.format('#'*(progress/10), progress) 

,這將給你是這樣的:[ ########## ] 100%

+0

執行'\ r' + myPercentage打印輸出? – bobber205 2010-07-04 00:37:53

+16

執行'\ r',然後再把整行寫出來。基本上:'print(「\ rProgress:[{0:50s}] {1:.1f}%」。format('#'* int(amtDone * 50),amtDone * 100))',其中'amtDone'是一個介於0和1之間的浮點數。 – 2010-07-04 00:46:00

+0

@MikeDeSimone,看起來像是使用curses的最佳酒吧。 – mlissner 2012-01-15 06:25:00

11

這裏是用Python寫的一個進度的一個很好的例子:http://nadiana.com/animated-terminal-progress-bar-in-python

但是,如果你想自己動手寫。你可以使用curses模塊使事情變得更容易:)

也許更容易不是詛咒的詞。但是如果你想創造一個完整的cui而不是詛咒爲你處理很多東西。

[編輯] 由於舊的鏈接是死的我都忍了我自己的一個Python進度的版本,在這裏獲得:https://github.com/WoLpH/python-progressbar

+14

'curses'?更輕鬆?嗯.... – aviraldg 2010-07-04 00:45:48

+0

一篇優秀的文章,我打算給它一個鏈接,但無法在我的書籤中找到:) – 2010-07-04 00:46:45

+0

@Aviral Dasgupta:夠公平,更簡單可能不是合適的詞。它可以爲你節省很多工作,但這取決於你在找什麼。 – Wolph 2010-07-04 00:54:57

260

寫作「\ r」將光標移動回的開始線。

這將顯示一個百分比計:

import time 
import sys 

for i in range(100): 
    time.sleep(1) 
    sys.stdout.write("\r%d%%" % i) 
    sys.stdout.flush() 
+3

粘貼並跑了。它每次打印一個新行。我想要在同一行上更新號碼。 :) – bobber205 2010-07-04 01:14:37

+0

@ bobber205:我剛剛嘗試過兩種不同的操作系統(mac和linux),兩種不同版本的python。它在一行上打印。 :)你確定你在'print'語句的末尾加了','嗎? – Stephen 2010-07-04 01:31:35

+0

我正在使用python 2.6 我在Aptana工作室和命令行嘗試過。打印多行。 :( – bobber205 2010-07-04 01:32:08

6

運行此在Python的命令行任何IDE或開發環境不):我的Windows系統上

>>> import threading 
>>> for i in range(50+1): 
... threading._sleep(0.5) 
... print "\r%3d" % i, ('='*i)+('-'*(50-i)), 

工作正常。

2
import sys 
def progresssbar(): 
     for i in range(100): 
      time.sleep(1) 
      sys.stdout.write("%i\r" % i) 

progressbar() 

注:如果您在互動interepter運行此你獲得額外的數字打印出來

4

我使用progress from reddit。我喜歡它,因爲它可以在一行中打印每個項目的進度,並且它不應該從程序中清除打印輸出。

編輯:固定鏈接

+1

你的鏈接被破壞 - 源代碼中的實際行是1274th,不是第1124!所以,正確的鏈接是這一個:https://github.com/reddit/reddit/blob/master/r2/r2/lib/utils/utils.py#L1274 – 2016-05-09 19:39:51

+0

這個變種有我的口味最好的設計:它使用迭代器並可能與任何可測量的工作一起工作,它顯示已用時間。 – 2016-05-09 19:43:37

17

檢查這個庫:clint

它有很多的功能,包括一個進度條:

from time import sleep 
from random import random 
from clint.textui import progress 
if __name__ == '__main__': 
    for i in progress.bar(range(100)): 
     sleep(random() * 0.2) 

    for i in progress.dots(range(100)): 
     sleep(random() * 0.2) 

這個link了其功能的簡要概述

29

我意識到自己遲到了,但是這裏有一個我寫的輕微的Yum風格(紅帽)(不適合100 %的精度在這裏,但如果您使用的是準確的該級別的進度條,那麼你就錯了反正):

import sys 

def cli_progress_test(end_val, bar_length=20): 
    for i in xrange(0, end_val): 
     percent = float(i)/end_val 
     hashes = '#' * int(round(percent * bar_length)) 
     spaces = ' ' * (bar_length - len(hashes)) 
     sys.stdout.write("\rPercent: [{0}] {1}%".format(hashes + spaces, int(round(percent * 100)))) 
     sys.stdout.flush() 

應該產生一種看起來像這樣:

Percent: [##############  ] 69% 

.. 。支架保持靜止,只有散列增加。

這可能會更好地作爲裝飾工作。另一天...

2

LOL我只是寫了這個 繼承人的代碼整體啄記住,你不能使用unicode做塊ASCII當我使用CP437

import os 
import time 
def load(left_side, right_side, length, time): 
    x = 0 
    y = "" 
    print "\r" 
    while x < length: 
     space = length - len(y) 
     space = " " * space 
     z = left + y + space + right 
     print "\r", z, 
     y += "█" 
     time.sleep(time) 
     x += 1 
    cls() 

,並調用它像這樣

print "loading something awesome" 
load("|", "|", 10, .01) 

,所以它看起來像這樣

loading something awesome 
|█████  | 
3
基礎上,現代單片機

e關於CLI進度條的答案和其他類似問題,我想我對所有人都有一個普遍的答案。檢查它在https://stackoverflow.com/a/15860757/2254146

綜上所述,代碼是這樣的:

import time, sys 

# update_progress() : Displays or updates a console progress bar 
## Accepts a float between 0 and 1. Any int will be converted to a float. 
## A value under 0 represents a 'halt'. 
## A value at 1 or bigger represents 100% 
def update_progress(progress): 
    barLength = 10 # Modify this to change the length of the progress bar 
    status = "" 
    if isinstance(progress, int): 
     progress = float(progress) 
    if not isinstance(progress, float): 
     progress = 0 
     status = "error: progress var must be float\r\n" 
    if progress < 0: 
     progress = 0 
     status = "Halt...\r\n" 
    if progress >= 1: 
     progress = 1 
     status = "Done...\r\n" 
    block = int(round(barLength*progress)) 
    text = "\rPercent: [{0}] {1}% {2}".format("#"*block + "-"*(barLength-block), progress*100, status) 
    sys.stdout.write(text) 
    sys.stdout.flush() 

貌似

百分比:[##########] 99.0%

2

隨着上面的偉大建議我制定了進度條。

不過我想指出一些不足之處

  1. 每次進度條被刷新,就會啓動一個新行

    print('\r[{0}]{1}%'.format('#' * progress* 10, progress)) 
    

    這樣的:
    [] 0 %
    [#] 10%
    [##] 20%
    [###] 30%

2.方括號']'和右側的百分數右移,因爲'###'變長。
3.如果表達式'progress/10'不能返回整數,則會發生錯誤。

而下面的代碼將解決上述問題。

def update_progress(progress, total): 
    print('\r[{0:10}]{1:>2}%'.format('#' * int(progress * 10 /total), progress), end='') 
0

那麼這裏是代碼的工作,我在發佈前測試過它:

import sys 
def prg(prog, fillchar, emptchar): 
    fillt = 0 
    emptt = 20 
    if prog < 100 and prog > 0: 
     prog2 = prog/5 
     fillt = fillt + prog2 
     emptt = emptt - prog2 
     sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%") 
     sys.stdout.flush() 
    elif prog >= 100: 
     prog = 100 
     prog2 = prog/5 
     fillt = fillt + prog2 
     emptt = emptt - prog2 
     sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nDone!") 
     sys.stdout.flush() 
    elif prog < 0: 
     prog = 0 
     prog2 = prog/5 
     fillt = fillt + prog2 
     emptt = emptt - prog2 
     sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nHalted!") 
     sys.stdout.flush() 

優點:

  • 20字符巴(1個字符,每5(數字明智))
  • 自定義填充字符
  • 自定義空字符
  • 暫停(任何數量低於0)
  • 完成(100和任何數量的上述100)
  • 進展計數(0-100(低於和高於用於特殊功能))下吧
  • 百分比數,和這是一個單行

缺點:

  • 僅支持整數(它可以被修改,以支持他們,雖然,通過使分工整數除法,所以只是改變prog2 = prog/5prog2 = int(prog/5)
0

這裏是我的Python 3溶液:

import time 
for i in range(100): 
    time.sleep(1) 
    s = "{}% Complete".format(i) 
    print(s,end=len(s) * '\b') 

'\ B' 是一個反斜槓,在您的字符串的每個字符。 這在Windows cmd窗口中不起作用。

7

和,只是添加到一堆,這裏是一個對象,你可以使用

import sys 

class ProgressBar(object): 
    DEFAULT_BAR_LENGTH = 65 
    DEFAULT_CHAR_ON = '=' 
    DEFAULT_CHAR_OFF = ' ' 

    def __init__(self, end, start=0): 
     self.end = end 
     self.start = start 
     self._barLength = self.__class__.DEFAULT_BAR_LENGTH 

     self.setLevel(self.start) 
     self._plotted = False 

    def setLevel(self, level): 
     self._level = level 
     if level < self.start: self._level = self.start 
     if level > self.end: self._level = self.end 

     self._ratio = float(self._level - self.start)/float(self.end - self.start) 
     self._levelChars = int(self._ratio * self._barLength) 

    def plotProgress(self): 
     sys.stdout.write("\r %3i%% [%s%s]" %(
      int(self._ratio * 100.0), 
      self.__class__.DEFAULT_CHAR_ON * int(self._levelChars), 
      self.__class__.DEFAULT_CHAR_OFF * int(self._barLength - self._levelChars), 
     )) 
     sys.stdout.flush() 
     self._plotted = True 

    def setAndPlot(self, level): 
     oldChars = self._levelChars 
     self.setLevel(level) 
     if (not self._plotted) or (oldChars != self._levelChars): 
      self.plotProgress() 

    def __add__(self, other): 
     assert type(other) in [float, int], "can only add a number" 
     self.setAndPlot(self._level + other) 
     return self 
    def __sub__(self, other): 
     return self.__add__(-other) 
    def __iadd__(self, other): 
     return self.__add__(other) 
    def __isub__(self, other): 
     return self.__add__(-other) 

    def __del__(self): 
     sys.stdout.write("\n") 

if __name__ == "__main__": 
    import time 
    count = 150 
    print "starting things:" 

    pb = ProgressBar(count) 

    #pb.plotProgress() 
    for i in range(0, count): 
     pb += 1 
     #pb.setAndPlot(i + 1) 
     time.sleep(0.01) 
    del pb 

    print "done" 

結果:

starting things: 
    100% [=================================================================] 
done 

這將最常被認爲是「潔癖」,但它的方便,當你使用它很多

+0

謝謝你。小的修復,plotProgress方法應該使用sys.stdout.flush()行,否則在任務完成之前可能不會繪製進度條(如mac終端中所示)。 – osnoz 2014-12-04 16:49:09

+0

我喜歡這個!相當容易使用! Thankyou – Microos 2017-03-08 04:40:20

50

它少於10行代碼。

的此處要點是:https://gist.github.com/vladignatyev/06860ec2040cb497f0f3

import sys 


def progress(count, total, suffix=''): 
    bar_len = 60 
    filled_len = int(round(bar_len * count/float(total))) 

    percents = round(100.0 * count/float(total), 1) 
    bar = '=' * filled_len + '-' * (bar_len - filled_len) 

    sys.stdout.write('[%s] %s%s ...%s\r' % (bar, percents, '%', suffix)) 
    sys.stdout.flush() # As suggested by Rom Ruben 

enter image description here

+2

將「sys.stdout.flush()」添加到函數的結尾。 – RomRuben 2015-07-07 11:25:44

+0

對我來說,它在一個新的行 – 2017-05-04 13:31:47

+0

@GM你使用什麼操作系統/平臺? – 2017-05-05 14:47:09

10
import time,sys 

for i in range(100+1): 
    time.sleep(0.1) 
    sys.stdout.write(('='*i)+(''*(100-i))+("\r [ %d"%i+"% ] ")) 
    sys.stdout.flush() 

輸出

[29%] ================= ==

37

嘗試使用由Python Mozart,Armin Ronacher編寫的click庫。

$ pip install click # both 2 and 3 compatible 

要創建一個簡單的進度條:

import click 

with click.progressbar(range(1000000)) as bar: 
    for i in bar: 
     pass 

這是什麼樣子:

# [###-------------------------------] 9% 00:01:14 

自定義你的心內容:

import click, sys 

with click.progressbar(range(100000), file=sys.stderr, show_pos=True, width=70, bar_template='(_(_)=%(bar)sD(_(_| %(info)s', fill_char='=', empty_char=' ') as bar: 
    for i in bar: 
     pass 

自定義外觀:

(_(_)===================================D(_(_| 100000/100000 00:00:02 

甚至有更多的選擇,請參閱API docs

click.progressbar(iterable=None, length=None, label=None, show_eta=True, show_percent=None, show_pos=False, item_show_func=None, fill_char='#', empty_char='-', bar_template='%(label)s [%(bar)s] %(info)s', info_sep=' ', width=36, file=None, color=None) 
+20

「自定義外觀」主題的有趣選擇 – Fuzz 2015-08-14 05:24:56

+5

那些菸頭? did_ಠ – wswld 2015-08-21 08:46:41

+5

我不打算代表任何東西。看起來像它代表了一個Rorshcach測試:/ – 2015-08-21 11:19:58

1

爲Python終端進度條代碼

import sys 
import time 

max_length = 5 
at_length = max_length 
empty = "-" 
used = "%" 

bar = empty * max_length 

for i in range(0, max_length): 
    at_length -= 1 

    #setting empty and full spots 
    bar = used * i 
    bar = bar+empty * at_length 

    #\r is carriage return(sets cursor position in terminal to start of line) 
    #\0 character escape 

    sys.stdout.write("[{}]\0\r".format(bar)) 
    sys.stdout.flush() 

    #do your stuff here instead of time.sleep 
    time.sleep(1) 

sys.stdout.write("\n") 
sys.stdout.flush() 
3

我建議使用tqdm - https://pypi.python.org/pypi/tqdm - 這使得它簡單把任何可迭代或加工成一個進度條,並處理所有與所需終端搞亂。

從文檔: 「tqdm可以很容易地支持回調/鉤和手動更新以下是包含的urllib示例」 從青枝

import urllib 
from tqdm import tqdm 

def my_hook(t): 
    """ 
    Wraps tqdm instance. Don't forget to close() or __exit__() 
    the tqdm instance once you're done with it (easiest using `with` syntax). 

    Example 
    ------- 

    >>> with tqdm(...) as t: 
    ...  reporthook = my_hook(t) 
    ...  urllib.urlretrieve(..., reporthook=reporthook) 

    """ 
    last_b = [0] 

    def inner(b=1, bsize=1, tsize=None): 
    """ 
    b : int, optional 
     Number of blocks just transferred [default: 1]. 
    bsize : int, optional 
     Size of each block (in tqdm units) [default: 1]. 
    tsize : int, optional 
     Total size (in tqdm units). If [default: None] remains unchanged. 
    """ 
    if tsize is not None: 
     t.total = tsize 
    t.update((b - last_b[0]) * bsize) 
    last_b[0] = b 
    return inner 

eg_link = 'http://www.doc.ic.ac.uk/~cod11/matryoshka.zip' 
with tqdm(unit='B', unit_scale=True, miniters=1, 
      desc=eg_link.split('/')[-1]) as t: # all optional kwargs 
    urllib.urlretrieve(eg_link, filename='/dev/null', 
         reporthook=my_hook(t), data=None) 
0

功能爲2.7:

def printProgressBar (iteration, total, prefix = '', suffix = '',decimals = 1, length = 100, fill = '#'): 

percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration/float(total))) 
filledLength = int(length * iteration // total) 
bar = fill * filledLength + '-' * (length - filledLength) 
print'\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), 
sys.stdout.flush() 
# Print New Line on Complete                                                    
if iteration == total: 
    print() 
0

蛇皮模塊進度條是一個不錯的選擇。 這裏是我的典型代碼:

import time 
import progressbar 

widgets = [ 
    ' ', progressbar.Percentage(), 
    ' ', progressbar.SimpleProgress(format='(%(value_s)s of %(max_value_s)s)'), 
    ' ', progressbar.Bar('>', fill='.'), 
    ' ', progressbar.ETA(format_finished='- %(seconds)s -', format='ETA: %(seconds)s',), 
    ' - ', progressbar.DynamicMessage('loss'), 
    ' - ', progressbar.DynamicMessage('error'), 
    '       ' 
] 

bar = progressbar.ProgressBar(redirect_stdout=True, widgets=widgets) 
bar.start(100) 
for i in range(100): 
    time.sleep(0.1) 
    bar.update(i + 1, loss=i/100., error=i) 
bar.finish() 
0

我寫了一個簡單的進度:

def bar(total, current, length=10, prefix="", filler="#", space=" ", oncomp="", border="[]", suffix=""): 
    if len(border) != 2: 
     print("parameter 'border' must include exactly 2 symbols!") 
     return None 

    print(prefix + border[0] + (filler * int(current/total * length) + 
             (space * (length - int(current/total * length)))) + border[1], suffix, "\r", end="") 
    if total == current: 
     if oncomp: 
      print(prefix + border[0] + space * int(((length - len(oncomp))/2)) + 
        oncomp + space * int(((length - len(oncomp))/2)) + border[1], suffix) 
     if not oncomp: 
      print(prefix + border[0] + (filler * int(current/total * length) + 
             (space * (length - int(current/total * length)))) + border[1], suffix) 

,你可以看到,它有:

from time import sleep, time 
start_time = time() 
for i in range(10): 
    pref = str((i+1) * 10) + "% " 
    complete_text = "done in %s sec" % str(round(time() - start_time)) 
    sleep(1) 
    bar(10, i + 1, length=20, prefix=pref, oncomp=complete_text) 
:巴,前綴和後綴,填料,空間,在文本條上的100%(oncomp)和邊界

這裏的示例的長度

了進展:

30% [######    ] 

出來完成:

100% [ done in 9 sec ] 
1

放在一起的一些我發現這裏的想法,並增加估計剩餘時間:

import datetime, sys 

start = datetime.datetime.now() 

def print_progress_bar (iteration, total): 

    process_duration_samples = [] 
    average_samples = 5 

    end = datetime.datetime.now() 

    process_duration = end - start 

    if len(process_duration_samples) == 0: 
     process_duration_samples = [process_duration] * average_samples 

    process_duration_samples = process_duration_samples[1:average_samples-1] + [process_duration] 
    average_process_duration = sum(process_duration_samples, datetime.timedelta())/len(process_duration_samples) 
    remaining_steps = total - iteration 
    remaining_time_estimation = remaining_steps * average_process_duration 

    bars_string = int(float(iteration)/float(total) * 20.) 
    sys.stdout.write(
     "\r[%-20s] %d%% (%s/%s) Estimated time left: %s" % (
      '='*bars_string, float(iteration)/float(total) * 100, 
      iteration, 
      total, 
      remaining_time_estimation 
     ) 
    ) 
    sys.stdout.flush() 
    if iteration + 1 == total: 
     print 


# Sample usage 

for i in range(0,300): 
    print_progress_bar(i, 300) 
2

安裝tqdmpip install tqdm) 並如下使用它:

import time 
from tqdm import tqdm 
for i in tqdm(range(1000)): 
    time.sleep(0.01) 

這是會輸出這樣的10秒作爲一個進度條:

47%|██████████████████▊      | 470/1000 [00:04<00:05, 98.61it/s]