Pythonのコンソール出力を置き換える


106

特定のC / C ++プログラムのように、Pythonでこれらの気の利いたコンソールカウンターの1つを作成する方法を知りたいです。

私は物事を行うループがあり、現在の出力は次の行に沿っています:

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

最後の行を更新するだけで、よりきれいになります。

X things done.

私はこれをいくつかのコンソールプログラムで見たことがありますが、Pythonでこれを行うかどうか、どのように行うのか疑問に思っています。


3
cursesを見てください。
ビョルンポレックス

2
ただ使用してくださいprintstackoverflow.com/a/8436827/1959808
Ioannis Filippidis 2015

1
@BjörnPollexはやりcursesすぎです(受け入れられた回答を参照)。
Alexey

回答:


151

簡単な解決策は"\r"、文字列の前に書き込むだけで、改行を追加しないことです。文字列が短くならない場合はこれで十分です...

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

もう少し洗練されているのはプログレスバーです...これは私が使っているものです:

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

あなたstartProgressは操作の説明を渡すことを呼び出し、次にprogress(x)どこxにパーセンテージがあり、最後にendProgress()


2
文字列が前のものより短い場合はどうなりますか?
math2001

6
空白による@ math2001パディング。
felipsmartins 2017

最初の2行のコードのみに投票しました。場合によっては、進行状況バーの部分が遅くなります。とにかく@ 6502に感謝
WaterRocket8236 2017年

一部のプログラム(resticflatpak)は、コンソール出力の数行を更新できます。どうすればこれを達成できるか知っていますか?
Alexey

1
@Alexey:ANSIエスケープコードを使用してカーソルを移動したり、画面の一部をクリアしたり、色を変更したりできます... en.wikipedia.org/wiki/ANSI_escape_code
6502

39

よりエレガントなソリューションは次のとおりです。

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

valueand endvalueでこの関数を呼び出すと、結果は

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

注:こちらの Python 2.xバージョン。


進行状況バーとスピナーを改善するには、Haloを使用する必要があります。
Aravind Voggu

17

python 3あなたは、同じ行に印刷するには、この操作を行うことができます。

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

最新の更新と進行状況を追跡するのに特に役立ちます。

ループの進行状況を確認したい場合は、ここからtqdm お勧めします。現在のイテレーションと合計イテレーションを、終了予定時刻を示すプログレスバーとして出力します。超便利で迅速。python2とpython3で動作します。


7

他の答えの方が良いかもしれませんが、これが私がやっていたことです。まず、バックスペース文字を出力するProgressという関数を作成しました。

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

次に、メイン関数のループで次のように呼び出しました。

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

もちろん、これにより行全体が消去されますが、これを台無しにして、希望どおりに実行することができます。私はこの方法を使用してプログレスバーを作成することになりました。


4
機能しますが、前の行に次の行よりも多くの文字がある場合、新しい行の終わり以降の文字は前の行から残ります。 "
Lil'sビット、

7

この数年後に偶然に遭遇した人のために(私のように)、6502のメソッドを少し調整して、プログレスバーを増減できるようにしました。少し多くの場合に役立ちます。素晴らしいツールをありがとう6502!

基本的に、唯一の違いは、progress(x)が呼び出されるたびに#sと-sの行全体が書き込まれ、カーソルが常にバーの先頭に戻ることです。

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
ただし、コードによって頻繁に呼び出されると、速度が低下する可能性があるので、YMMV
jat255

6

私はよく理解した場合(ないように注意してください)あなたが使用して印刷したい<CR>といませんか<LR>

可能であれば、コンソール端末がこれを許可している限り、これが可能です(出力がファイルにリダイレクトされると中断します)。

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

5

print()関数を見ると、sysライブラリを使用せずに実行できます。

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

これが私のコードです:

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

5

これは少し前に書いたもので、本当に満足しています。お気軽にご利用ください。

indexand totalとオプションでtitleorを取りますbar_length。完了したら、砂時計をチェックマークに置き換えます。

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

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

それをテストするために実行できる例を含めました。

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)

またshutil.get_terminal_size()、関心がある場合は、使用している端末の幅に応じて、応答バーが表示されるバージョンもあります。


4

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

これで、前のバーを置き換えることなく、複数のプログレスバーを生成できます。

name固定幅の値としても追加しました。

2つのループと2回progressBar()の結果の使用は次のようになります。

プログレスバーアニメーション


-1

以下のコードは、0.3秒ごとに0から137までのメッセージをカウントし、前の数値を置き換えます。

バックステージへのシンボルの数=桁数。

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.