Ganti keluaran konsol dengan Python


106

Saya bertanya-tanya bagaimana saya bisa membuat salah satu penghitung konsol yang bagus dengan Python seperti dalam program C / C ++ - tertentu.

Saya mendapat loop yang melakukan sesuatu dan output saat ini berada di sepanjang baris:

Doing thing 0
Doing thing 1
Doing thing 2
...

apa yang akan lebih rapi jika hanya memiliki pembaruan baris terakhir;

X things done.

Saya telah melihat ini di sejumlah program konsol dan bertanya-tanya apakah / bagaimana saya akan melakukan ini dengan Python.


3
Anda harus melihat kutukan .
Björn Pollex


1
@ BjörnPollex, terlalu cursesberlebihan (lihat jawaban yang diterima).
Alexey

Jawaban:


151

Solusi yang mudah hanyalah menulis "\r"sebelum string dan tidak menambahkan baris baru; jika string tidak pernah menjadi lebih pendek ini sudah cukup ...

sys.stdout.write("\rDoing thing %i" % i)
sys.stdout.flush()

Sedikit lebih canggih adalah bilah kemajuan ... ini adalah sesuatu yang saya gunakan:

def startProgress(title):
    global progress_x
    sys.stdout.write(title + ": [" + "-"*40 + "]" + chr(8)*41)
    sys.stdout.flush()
    progress_x = 0

def progress(x):
    global progress_x
    x = int(x * 40 // 100)
    sys.stdout.write("#" * (x - progress_x))
    sys.stdout.flush()
    progress_x = x

def endProgress():
    sys.stdout.write("#" * (40 - progress_x) + "]\n")
    sys.stdout.flush()

Anda menyebut startProgresslewat deskripsi operasi, lalu di progress(x)mana xpersentase dan akhirnyaendProgress()


2
Bagaimana jika stringnya lebih pendek dari yang sebelumnya?
math2001

6
@ math2001 mengisi dengan spasi kosong.
felipsmartins

Memilih hanya untuk 2 baris kode pertama. Bagian bilah kemajuan menjadi lambat dalam beberapa kasus. Pokoknya Terima kasih @ 6502
WaterRocket8236

Beberapa program ( restic, flatpak) dapat memperbarui beberapa baris keluaran konsol. Apakah Anda tahu secara kebetulan bagaimana ini bisa dicapai?
Alexey

1
@Alexey: Anda dapat menggunakan kode pelolosan ANSI untuk memindahkan kursor, menghapus bagian layar dan mengubah warna ... lihat en.wikipedia.org/wiki/ANSI_escape_code
6502

39

Solusi yang lebih elegan bisa jadi:

def progressBar(current, total, barLength = 20):
    percent = float(current) * 100 / total
    arrow   = '-' * int(percent/100 * barLength - 1) + '>'
    spaces  = ' ' * (barLength - len(arrow))

    print('Progress: [%s%s] %d %%' % (arrow, spaces, percent), end='\r')

panggil fungsi ini dengan valuedan endvalue, hasilnya harus

Progress: [------------->      ] 69 %

Catatan: Versi Python 2.x disini .


Anda harus menggunakan Halo untuk bilah kemajuan dan pemintal yang lebih baik.
Aravind Voggu

18

Di python 3 Anda dapat melakukan ini untuk mencetak pada baris yang sama:

print('', end='\r')

Sangat berguna untuk melacak pembaruan dan kemajuan terbaru.

Saya juga merekomendasikan tqdm dari sini jika seseorang ingin melihat kemajuan sebuah loop. Ini mencetak iterasi saat ini dan iterasi total sebagai bilah perkembangan dengan waktu penyelesaian yang diharapkan. Sangat berguna dan cepat. Bekerja untuk python2 dan python3.


7

Jawaban lain mungkin lebih baik, tapi inilah yang saya lakukan. Pertama, saya membuat fungsi yang disebut kemajuan yang mencetak karakter spasi mundur:

def progress(x):
    out = '%s things done' % x  # The output
    bs = '\b' * 1000            # The backspace
    print bs,
    print out,

Lalu saya menyebutnya dalam satu lingkaran di fungsi utama saya seperti:

def main():
    for x in range(20):
        progress(x)
    return

Ini tentu saja akan menghapus seluruh baris, tetapi Anda dapat mengacaukannya untuk melakukan apa yang Anda inginkan. Saya akhirnya membuat bilah kemajuan menggunakan metode ini.


4
Berfungsi, tetapi jika baris sebelumnya memiliki lebih banyak karakter daripada baris berikutnya, karakter setelah akhir baris baru tetap ada dari baris sebelumnya: "Catatan pemeriksaan ejaan 417/701 [pelayanan diubah ke permukaan] saat] uminescence] cence] shmentarianism] "
Lil 'Bits

7

Bagi siapa pun yang tersandung pada tahun-tahun ini kemudian (seperti yang saya lakukan), saya mengubah metode 6502 sedikit untuk memungkinkan bilah kemajuan menurun dan juga meningkat. Berguna dalam lebih banyak kasus. Terima kasih 6502 untuk alat yang hebat!

Pada dasarnya, satu-satunya perbedaan adalah bahwa seluruh baris #s dan -s ditulis setiap kali kemajuan (x) dipanggil, dan kursor selalu dikembalikan ke awal bilah.

def startprogress(title):
    """Creates a progress bar 40 chars long on the console
    and moves cursor back to beginning with BS character"""
    global progress_x
    sys.stdout.write(title + ": [" + "-" * 40 + "]" + chr(8) * 41)
    sys.stdout.flush()
    progress_x = 0


def progress(x):
    """Sets progress bar to a certain percentage x.
    Progress is given as whole percentage, i.e. 50% done
    is given by x = 50"""
    global progress_x
    x = int(x * 40 // 100)                      
    sys.stdout.write("#" * x + "-" * (40 - x) + "]" + chr(8) * 41)
    sys.stdout.flush()
    progress_x = x


def endprogress():
    """End of progress bar;
    Write full bar, then move to next line"""
    sys.stdout.write("#" * 40 + "]\n")
    sys.stdout.flush()

1
Saya telah menemukan bahwa ini dapat menyebabkan beberapa perlambatan jika dipanggil terlalu sering oleh kode, jadi saya rasa YMMV
jat255

6

Jika saya mengerti dengan baik (tidak yakin) Anda ingin mencetak menggunakan <CR>dan tidak <LR>?

Jika demikian ini dimungkinkan, selama terminal konsol memungkinkan ini (itu akan rusak ketika output dialihkan ke file).

from __future__ import print_function
print("count x\r", file=sys.stdout, end=" ")

5

Itu bisa dilakukan tanpa menggunakan perpustakaan sys jika kita melihat print()fungsinya

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Ini kode saya:

def update(n):
    for i in range(n):
        print("i:",i,sep='',end="\r",flush=True)
        #time.sleep(1)

5

Saya menulis ini beberapa waktu yang lalu dan sangat senang dengannya. Jangan ragu untuk menggunakannya.

Dibutuhkan indexdan totaldan secara opsional titleatau bar_length. Setelah selesai, ganti kaca jam dengan tanda centang.

⏳ Calculating: [████░░░░░░░░░░░░░░░░░░░░░] 18.0% done

✅ Calculating: [█████████████████████████] 100.0% done

Saya menyertakan contoh yang bisa dijalankan untuk mengujinya.

import sys
import time

def print_percent_done(index, total, bar_len=50, title='Please wait'):
    '''
    index is expected to be 0 based index. 
    0 <= index < total
    '''
    percent_done = (index+1)/total*100
    percent_done = round(percent_done, 1)

    done = round(percent_done/(100/bar_len))
    togo = bar_len-done

    done_str = '█'*int(done)
    togo_str = '░'*int(togo)

    print(f'\t⏳{title}: [{done_str}{togo_str}] {percent_done}% done', end='\r')

    if round(percent_done) == 100:
        print('\t✅')


r = 50
for i in range(r):
    print_percent_done(i,r)
    time.sleep(.02)

Saya juga memiliki versi dengan bilah kemajuan responsif tergantung pada lebar terminal yang digunakan shutil.get_terminal_size()jika itu menarik.


4

Menambahkan sedikit lebih banyak fungsionalitas ke contoh Aravind Voggu :

def progressBar(name, value, endvalue, bar_length = 50, width = 20):
        percent = float(value) / endvalue
        arrow = '-' * int(round(percent*bar_length) - 1) + '>'
        spaces = ' ' * (bar_length - len(arrow))
        sys.stdout.write("\r{0: <{1}} : [{2}]{3}%".format(\
                         name, width, arrow + spaces, int(round(percent*100))))
        sys.stdout.flush()
        if value == endvalue:     
             sys.stdout.write('\n\n')

Sekarang Anda dapat membuat beberapa bilah kemajuan tanpa mengganti yang sebelumnya.

Saya juga menambahkan namesebagai nilai dengan lebar tetap.

Untuk dua loop dan dua kali penggunaan progressBar()hasilnya akan terlihat seperti:

animasi progress bar


-1

Kode di bawah ini akan menghitung Pesan dari 0 hingga 137 setiap 0,3 detik menggantikan nomor sebelumnya.

Jumlah simbol ke belakang panggung = jumlah digit.

stream = sys.stdout
for i in range(137):
    stream.write('\b' * (len(str(i)) + 10))
    stream.write("Message : " + str(i))
    stream.flush()
    time.sleep(0.3)
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.