Python untuk mencetak bilah status dan persentase


160

Untuk menerapkan bilah status seperti di bawah ini:

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

Saya ingin ini dicetak ke stdout, dan terus menyegarkan, bukan mencetak ke baris lain. Bagaimana cara melakukannya?


Saya telah menerbitkan jenis progress bar baru, yang dapat Anda cetak, lihat throughput dan eta, bahkan menghentikannya, di samping animasi yang sangat keren! Silakan lihat: github.com/rsalmei/alive-progress ! hidup-kemajuan
rsalmei

Jawaban:


146

Ada modul Python yang bisa Anda dapatkan dari PyPI yang disebut progressbaryang mengimplementasikan fungsi tersebut. Jika Anda tidak keberatan menambahkan ketergantungan, itu adalah solusi yang bagus. Kalau tidak, pergilah dengan salah satu jawaban lain.

Contoh sederhana cara menggunakannya:

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()

Untuk menginstalnya, Anda dapat menggunakan easy_install progressbar, atau pip install progressbarjika Anda lebih suka pip.


Semua jawaban itu mengagumkan, namun, saya paling suka modul. Terima kasih semuanya.
Stan

8
Mungkin contoh ini membutuhkan sesuatu seperti bar.start()?
Jim Raynor

2
Tidak berfungsi pada mesin saya — perlu ditambahkanbar.start()
Zach

1
Modul ini belum diperbarui dalam lebih dari 2 tahun. Jangan menggunakannya untuk perangkat lunak baru!
Navin

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

254

The '\r'karakter (carriage return) me-reset kursor ke awal baris dan memungkinkan Anda untuk menulis lebih apa yang sebelumnya di telepon.

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)

Saya tidak 100% yakin apakah ini sepenuhnya portabel di semua sistem, tetapi paling tidak bekerja di Linux dan OSX.


7
Ini lebih baik daripada jawaban yang ditandai, karena ia bekerja dengan Python 3 juga.
Gerhard Hagerer

tahu mengapa saya mendapatkan karakter aneh di akhir baris kadang-kadang, bahkan jika saya null-mengakhiri string yang sedang ditulis?
reservoirman

23
Seperti yang tertulis, kode tidak menjelaskan bagaimana mengadaptasi ini dengan ukuran apa pun yang Anda iterasi (bukan 21). Aku akan membiarkan n=21, ganti range(21)dengan range(n), kemudian tambahkan j = (i + 1) / ndalam loop, dan mengganti writepernyataan dengan sedikit modifikasi ini: sys.stdout.write("[%-20s] %d%%" % ('='*int(20*j), 100*j)). Sekarang satu-satunya perubahan yang perlu Anda lakukan adalah n=21sebelum loop (lebih mungkin n=len(iterable)), kemudian menghitung lebih dari objek iterable. Saya merekomendasikan suntingan ini tetapi ditolak; rupanya fungsionalitas "menyimpang dari maksud asli kiriman".
Steven C. Howell

1
Adaptif dengan ukuran acak n,, sys.stdout.write("[{:{}}] {:.1f}%".format("="*i, n-1, (100/(n-1)*i)))hanya Python 3
GabrielChu

3
@ StevenC.Namun mengapa Anda tidak mempostingnya sebagai jawaban mengutip Mark? ini versi lain dan sangat membantu untuk menyiapkannya
GM

91

Saya menemukan tqdm perpustakaan yang bermanfaat ( https://github.com/tqdm/tqdm/ , sebelumnya: https://github.com/noamraph/tqdm ). Secara otomatis memperkirakan waktu penyelesaian dan dapat digunakan sebagai iterator.

Pemakaian:

import tqdm
import time

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

Hasil dalam:

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

tqdm dapat membungkus iterable.


4
Proyek tqdm sekarang dikelola di sini oleh tim pengembang baru.
Gaborous

1
waw, tqdm ini luar biasa, dan sangat mudah digunakan :).
Sidahmed

6
ini adalah solusi yang paling mudah
kd88

2
itu dibundel dengan distrib Anaconda juga! (Adapun python 3.5 dan di atas setidaknya)
Jacquot

Terima kasih, luar biasa, sederhana dan efektif
DavideL

23

Anda dapat menggunakan \r( carriage return ). 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()

Coba totalsebagai 10, maka Anda mendapatkan pesan kesalahanZeroDivisionError: long division or modulo by zero
unseen_rider

19

Di sini Anda dapat menggunakan kode berikut sebagai fungsi:

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()

Dengan menggunakan .format:

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()

Bagi saya, baris pertama tidak diubah oleh kursor - hanya baris kedua yang diubah. Oleh karena itu beberapa baris diperoleh untuk bilah kemajuan, dan satu untuk misalnya] percent * 100 %
unseen_rider

6

berdasarkan jawaban di atas dan pertanyaan serupa lainnya tentang bilah kemajuan CLI, saya pikir saya mendapat jawaban umum yang umum untuk semuanya. Periksa di https://stackoverflow.com/a/15860757/2254146

Berikut adalah salinan fungsi, tetapi dimodifikasi agar sesuai dengan gaya Anda:

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()

Seperti

Persen: [====================] 99,0%


Bilah progres tidak muncul untuk saya
unseen_rider

Saya pikir itu tidak membutuhkan banyak tempat desimal yaitu putaran (kemajuan * 100,2)
Andrés Sánchez

4

Jika Anda mengembangkan antarmuka baris perintah, saya sarankan Anda untuk melihat clickyang sangat bagus:

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)

Di sini output yang Anda dapatkan:

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

4

Peningkatan lebih lanjut, menggunakan fungsi sebagai:

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()

contoh panggilan:

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

keluaran:

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

sempurna! dan tidak ada modul yang diperlukan
yurividal

3

Saya menemukan utas ini hari ini dan setelah mencoba solusi ini dari Mark Rushakoff

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)

Saya dapat mengatakan bahwa ini berfungsi dengan baik pada W7-64 dengan python 3.4.3 64-bit tetapi hanya di konsol asli. Namun ketika menggunakan konsol built-in spyder 3.0.0dev, jeda baris masih ada / lagi. Karena ini perlu waktu bagi saya untuk mencari tahu, saya ingin melaporkan pengamatan ini di sini.


2

Membangun beberapa jawaban di sini dan di tempat lain, saya telah menulis fungsi sederhana ini yang menampilkan bilah kemajuan dan sisa waktu yang diperkirakan. Harus bekerja pada sebagian besar mesin berbasis unix.

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

Ini cukup pendekatan sederhana yang dapat digunakan dengan loop apa pun.

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

Apa yang dilakukan '#'?
unseen_rider

@unseen_rider Here '#' hanyalah simbol yang akan diulang seiring iterasi loop meningkat.
NILESH KUMAR

2

Paling mudah masih

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()

Kuncinya adalah untuk mengkonversi tipe integer ke string.


2

Seperti dijelaskan dalam solusi Mark Rushakoff , Anda dapat menampilkan karakter carriage return sys.stdout.write('\r'),, untuk mengatur ulang kursor ke awal baris. Untuk menggeneralisasi solusi itu, sambil juga mengimplementasikan f-Strings Python 3 , Anda bisa menggunakan

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

Coba PyProg. PyProg adalah pustaka sumber terbuka untuk Python untuk membuat indikator & bilah kemajuan yang dapat disesuaikan.

Saat ini di versi 1.0.2; di-host di Github dan tersedia di PyPI (Tautan di bawah). Ini kompatibel dengan Python 3 & 2 dan juga dapat digunakan dengan Qt Console.

Ini sangat mudah digunakan. Kode berikut:

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()

akan menghasilkan apa yang Anda inginkan (bahkan panjang bilah!):

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

Untuk opsi lainnya untuk menyesuaikan bilah kemajuan, buka halaman Github dari situs web ini.

Saya benar-benar membuat PyProg karena saya membutuhkan pustaka kemajuan sederhana namun super dapat dikustomisasi. Anda dapat dengan mudah menginstalnya dengan: pip install pyprog.

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


1

Menggunakan jawaban @ Mark-Rushakoff, saya berhasil menggunakan pendekatan yang lebih sederhana, tidak perlu memanggil perpustakaan sys. Ini bekerja dengan Python 3. Diuji di Windows:

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)

Seperti dijelaskan dalam jawaban untuk pertanyaan yang berbeda print adalah pembungkus tipis yang memformat input dan memanggil fungsi tulis dari objek yang diberikan. Secara default objek ini adalah sys.stdout.
Steven C. Howell

0

Ini adalah sesuatu yang saya buat menggunakan solusi oleh @ Mark-Rushakoff. Untuk menyesuaikan dengan lebar terminal secara adaptif.

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("")
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.