Durum çubuğunu ve yüzdesini yazdırmak için Python


160

Aşağıdaki gibi bir durum çubuğu uygulamak için:

[==========                ]  45%
[================          ]  60%
[==========================] 100%

Bunu stdout'a yazdırmak ve yenilemeye devam etmek istiyorum, başka bir satıra yazdırmamak istiyorum. Bu nasıl yapılır?


Çok güzel animasyonların yanı sıra yazdırabileceğiniz, iş hacmini ve etayı görebileceğiniz, hatta duraklatabileceğiniz yeni bir tür ilerleme çubuğu yayınladım! Lütfen bir göz atın: github.com/rsalmei/alive-progress ! canlı-ilerleme
rsalmei

Yanıtlar:


146

Eğer alabileceğiniz bir Python modülü var PyPI denilen progressbaruygular böyle bir işlevsellik de. Bir bağımlılık eklemeyi düşünmezseniz, bu iyi bir çözümdür. Aksi takdirde, diğer cevaplardan biriyle devam edin.

Nasıl kullanılacağına basit bir örnek:

import progressbar
from time import sleep
bar = progressbar.ProgressBar(maxval=20, \
    widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()])
bar.start()
for i in xrange(20):
    bar.update(i+1)
    sleep(0.1)
bar.finish()

Kurmak için kullanabilirsiniz easy_install progressbarveya pip install progressbarpip'i tercih ederseniz.


Tüm cevaplar harika, ancak modülü en çok seviyorum. Herkese teşekkürler.
Stan

8
Belki de bu örneğin bir şeye ihtiyacı vardır bar.start()?
Jim Raynor

2
Makinemde çalışmıyor - eklemek gerekiyorbar.start()
Zach

1
Bu modül 2 yıldan fazla bir süredir güncellenmemiştir. Yeni yazılım için kullanmayın!
Navin

4
Kurulum: sudo -H pip install progressbar2.
Martin Thoma

254

'\r'Karakteri (satırbaşı) satırın başına imleci sıfırlarsa ve on line önceden neydi üzerinde yazmasına olanak tanır.

from time import sleep
import sys

for i in range(21):
    sys.stdout.write('\r')
    # the exact output you're looking for:
    sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i))
    sys.stdout.flush()
    sleep(0.25)

Bunun tüm sistemlerde tamamen taşınabilir olup olmadığından% 100 emin değilim, ancak en azından Linux ve OSX üzerinde çalışıyor.


7
Bu işaretli cevaptan daha iyidir, çünkü Python 3 ile de çalışır.
Gerhard Hagerer

herhangi bir fikir neden bir satır sonunda bazen garip karakterler olsun, ben yazılmakta olan dize null-sonlandırmak bile?
reservoirman

23
Yazıldığı gibi, kod bunu yinelediğiniz boyuta (21 değil) nasıl uyarlayacağınızı netleştirmez. Ben izin verirdim n=21değiştirin range(21)ile range(n)daha sonra ekleyin j = (i + 1) / ndöngü içinde ve değiştirme writeBu ufak bir değişiklikle deyimi: sys.stdout.write("[%-20s] %d%%" % ('='*int(20*j), 100*j)). Şimdi yapmanız gereken tek değişiklik n=21döngüden önce (büyük olasılıkla n=len(iterable)), sonra tekrarlanabilir nesne üzerinde numaralandırmaktır. Bu düzenlemeyi tavsiye ettim ama reddedildi; Görünüşe göre işlevsellik "yazının orijinal niyetinden sapar".
Steven C. Howell

1
N,, sys.stdout.write("[{:{}}] {:.1f}%".format("="*i, n-1, (100/(n-1)*i)))sadece Python 3 keyfi boyutuyla uyarlanabilir
GabrielChu

3
@ StevenC.Howell, Mark'ı göstererek neden cevap vermiyorsun? başka bir versiyon ve hazırlanmak çok yararlı
GM

91

Yararlı kütüphane tqdm buldum ( daha önce https://github.com/tqdm/tqdm/ , https://github.com/noamraph/tqdm ). Tamamlanma süresini otomatik olarak tahmin eder ve yineleyici olarak kullanılabilir.

Kullanımı:

import tqdm
import time

for i in tqdm.tqdm(range(1000)):
    time.sleep(0.01)
    # or other long operations

Sonuçlar:

|####------| 450/1000  45% [elapsed: 00:04 left: 00:05, 99.15 iters/sec]

tqdm herhangi bir yinelenebilir sarın.


4
Tqdm projesi şimdi burada korunur geliştiricilerin yeni bir ekip tarafından.
gaborous

1
waw, bu tqdm sadece şaşırtıcı ve kullanımı çok kolay :).
Sidahmed

6
bu kolayca en basit çözümdür
kd88

2
Anaconda dağıtımı ile birlikte geliyor! (en azından python 3.5 ve üstü için)
Jakot

Teşekkürler, şaşırtıcı, basit ve etkili
DavideL

23

Kullanabilirsiniz \r( satırbaşı ). Demo:

import sys
total = 10000000
point = total / 100
increment = total / 20
for i in xrange(total):
    if(i % (5 * point) == 0):
        sys.stdout.write("\r[" + "=" * (i / increment) +  " " * ((total - i)/ increment) + "]" +  str(i / point) + "%")
        sys.stdout.flush()

Deneyin totalolarak 10o zaman hata mesajı alıyorum,ZeroDivisionError: long division or modulo by zero
unseen_rider

19

Burada aşağıdaki kodu bir işlev olarak kullanabilirsiniz:

def drawProgressBar(percent, barLen = 20):
    sys.stdout.write("\r")
    progress = ""
    for i in range(barLen):
        if i < int(barLen * percent):
            progress += "="
        else:
            progress += " "
    sys.stdout.write("[ %s ] %.2f%%" % (progress, percent * 100))
    sys.stdout.flush()

.Format kullanımı ile:

def drawProgressBar(percent, barLen = 20):
    # percent float from 0 to 1. 
    sys.stdout.write("\r")
    sys.stdout.write("[{:<{}}] {:.0f}%".format("=" * int(barLen * percent), barLen, percent * 100))
    sys.stdout.flush()

Benim için ilk satır imleç tarafından değiştirilmez - sadece ikinci satır değiştirir. Böylece ilerleme çubuğu için birden fazla satır, örneğin bir tane için] percent * 100 %
unseen_rider

6

Yukarıdaki yanıtlara ve CLI ilerleme çubuğu ile ilgili diğer benzer sorulara dayanarak, hepsine genel bir ortak yanıt aldım. Https://stackoverflow.com/a/15860757/2254146 adresinden kontrol edin

İşte işlevin bir kopyası, ancak stilinize uyacak şekilde değiştirilmiş:

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 = 20 # 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()

Gibi görünüyor

Yüzde: [====================]% 99.0


İlerleme çubuğu benim için görünmüyor
unseen_rider

Çok sayıda ondalık basamağa ihtiyaç olmadığını düşünüyorum (yani ilerleme * 100,2)
Andrés Sánchez

4

Bir komut satırı arayüzü geliştiriyorsanız, clickhangisinin çok güzel olduğuna bir göz atmanızı öneririm :

import click
import time

for filename in range(3):
    with click.progressbar(range(100), fill_char='=', empty_char=' ') as bar:
        for user in bar:
            time.sleep(0.01)

İşte çıktı:

$ python test.py
  [====================================]  100%
  [====================================]  100%
  [=========                           ]   27%

4

Bir işlevi aşağıdaki gibi kullanarak daha da iyileştirme:

import sys

def printProgressBar(i,max,postText):
    n_bar =10 #size of progress bar
    j= i/max
    sys.stdout.write('\r')
    sys.stdout.write(f"[{'=' * int(n_bar * j):{n_bar}s}] {int(100 * j)}%  {postText}")
    sys.stdout.flush()

çağrı örneği:

total=33
for i in range(total):
    printProgressBar(i,total,"blah")
    sleep(0.05)  

çıktı:

[================================================  ] 96%  blah  

mükemmel! ve modüle gerek yok
yurividal

3

Bugün bu konuya geldim ve Mark Rushakoff'un bu çözümünü denedikten sonra

from time import sleep
import sys

for i in range(21):
sys.stdout.write('\r')
# the exact output you're looking for:
sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i))
sys.stdout.flush()
sleep(0.25)

Bunun python 3.4.3 64 bit ile W7-64'de iyi çalıştığını söyleyebilirim, ancak sadece yerel konsolda. Ancak spyder 3.0.0dev'in yerleşik konsolunu kullanırken, satır sonları hala / yine mevcuttur. Bu bana biraz zaman ayırdığı için bu gözlemi burada bildirmek istiyorum.


2

Burada ve başka yerlerde bazı cevaplara dayanarak, bir ilerleme çubuğu ve geçen / tahmini kalan süreyi gösteren bu basit işlevi yazdım. Çoğu unix tabanlı makinede çalışmalıdır.

import time
import sys

percent = 50.0
start = time.time()
draw_progress_bar(percent, start)


def draw_progress_bar(percent, start, barLen=20):
sys.stdout.write("\r")
progress = ""
for i in range(barLen):
    if i < int(barLen * percent):
        progress += "="
    else:
        progress += " "

elapsedTime = time.time() - start;
estimatedRemaining = int(elapsedTime * (1.0/percent) - elapsedTime)

if (percent == 1.0):
    sys.stdout.write("[ %s ] %.1f%% Elapsed: %im %02is ETA: Done!\n" % 
        (progress, percent * 100, int(elapsedTime)/60, int(elapsedTime)%60))
    sys.stdout.flush()
    return
else:
    sys.stdout.write("[ %s ] %.1f%% Elapsed: %im %02is ETA: %im%02is " % 
        (progress, percent * 100, int(elapsedTime)/60, int(elapsedTime)%60,
         estimatedRemaining/60, estimatedRemaining%60))
    sys.stdout.flush()
    return

2

Bu oldukça basit bir yaklaşımdır, her döngüde kullanılabilir.

#!/usr/bin/python
for i in range(100001):
    s =  ((i/5000)*'#')+str(i)+(' %')
    print ('\r'+s),

'#' Ne yapar?
unseen_rider

@unseen_rider Burada '#' sadece döngü yinelemesi arttıkça tekrarlanacak bir semboldür.
NILESH KUMAR

2

En kolayı hala

import sys
total_records = 1000
for i in range (total_records):
    sys.stdout.write('\rUpdated record: ' + str(i) + ' of ' + str(total_records))
    sys.stdout.flush()

Anahtar, tamsayı türünü dizeye dönüştürmektir.


2

Mark Rushakoff'un çözümünde açıklandığı gibi sys.stdout.write('\r'), imleci satırın başına sıfırlamak için satır başı karakterini çıktılayabilirsiniz . Bu çözümü genelleştirmek için Python 3'ün f-String'lerini de uygularken kullanabilirsiniz

from time import sleep
import sys

n_bar = 50
iterable = range(33)  # for demo purposes
n_iter = len(iterable)
for i, item in enumerate(iterable):
    j = (i + 1) / n_iter

    sys.stdout.write('\r')
    sys.stdout.write(f"[{'=' * int(n_bar * j):{n_bar}s}] {int(100 * j)}%")
    sys.stdout.flush()

    sleep(0.05)  
    # do something with <item> here

1

PyProg'u deneyin. PyProg, Python'un süper özelleştirilebilir ilerleme göstergeleri ve çubukları oluşturması için açık kaynaklı bir kütüphanedir.

Şu anda 1.0.2 sürümündedir; Github'da barındırılır ve PyPI'de bulunur (Aşağıdaki bağlantılar). Python 3 ve 2 ile uyumludur ve Qt Console ile de kullanılabilir.

Kullanımı gerçekten çok kolay. Aşağıdaki kod:

import pyprog
from time import sleep

# Create Object
prog = pyprog.ProgressBar(" ", " ", total=34, bar_length=26, complete_symbol="=", not_complete_symbol=" ", wrap_bar_prefix=" [", wrap_bar_suffix="] ", progress_explain="", progress_loc=pyprog.ProgressBar.PROGRESS_LOC_END)
# Update Progress Bar
prog.update()

for i in range(34):
    # Do something
    sleep(0.1)
    # Set current status
    prog.set_stat(i + 1)
    # Update Progress Bar again
    prog.update()

# Make the Progress Bar final
prog.end()

tam olarak ne istediğinizi üretecektir (çubuk uzunluğu bile!):

[===========               ] 45%
[===============           ] 60%
[==========================] 100%

İlerleme çubuğunu özelleştirmek için daha fazla seçenek için bu web sitesinin Github sayfasına gidin.

Aslında PyProg yaptım çünkü basit ama süper özelleştirilebilir bir ilerleme çubuğu kütüphanesine ihtiyacım vardı. Kolayca ile yükleyebilirsiniz: pip install pyprog.

PyProg Github: https://github.com/Bill13579/pyprog
PyPI: https://pypi.python.org/pypi/pyprog/


1

@ Mark-Rushakoff cevabını kullanarak, daha basit bir yaklaşım geliştirdim, sys kütüphanesini çağırmaya gerek yok. Python 3 ile çalışır. Windows'ta test edilmiştir:

from time import sleep
for i in range(21):
    # the exact output you're looking for:
    print ("\r[%-20s] %d%%" % ('='*i, 5*i), end='')
    sleep(0.25)

Farklı bir sorunun cevabında açıklandığı gibi ,print girişi formatlayan ve belirli bir nesnenin yazma fonksiyonunu çağıran ince bir sargıdır. Varsayılan olarak bu nesne sys.stdout.
Steven C. Howell

0

İşte @ Mark-Rushakoff'un çözümünü kullanarak yaptığım bir şey. Terminal genişliğine uyum sağlamak için.

from time import sleep
import os
import sys
from math import ceil

l = list(map(int,os.popen('stty size','r').read().split()))
col = l[1]
col = col - 6

for i in range(col):
    sys.stdout.write('\r')
    getStr = "[%s " % ('='*i)
    sys.stdout.write(getStr.ljust(col)+"]"+"%d%%" % (ceil((100/col)*i)))
    sys.stdout.flush()
    sleep(0.25)
print("")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.