用 Python 替换控制台输出

我想知道如何像在某些 C/C + + 程序中那样在 Python 中创建一个漂亮的控制台计数器。

我有一个循环,当前输出是这样的:

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

更简洁的做法是只对最后一行进行更新;

X things done.

我在许多控制台程序中看到过这种情况,我想知道是否/如何在 Python 中实现这一点。

155376 次浏览

如果我理解得很好(不确定) ,你想打印使用 <CR>而不是 <LR>

如果可能,只要控制台终端允许(当输出 si 重定向到一个文件时,它就会中断)。

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

一个简单的解决方案就是在字符串之前写 "\r",而不添加换行符; 如果字符串从来没有变短过,这就足够了..。

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

稍微复杂一点的是一个进度条... 这是我正在使用的东西:

def start_progress(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 end_progress():
sys.stdout.write("#" * (40 - progress_x) + "]\n")
sys.stdout.flush()

通过操作描述调用 start_progress,然后调用 progress(x),其中 x是百分比,最后调用 end_progress()

另一个答案可能更好,但这是我正在做的。首先,我创建了一个名为 Progress 的函数,它可以打印出退格字符:

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

然后我在 main 函数中循环调用它,如下所示:

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

这当然会删除整个行,但是你可以随心所欲地做你想做的事情。最后,我用这种方法制作了一个进度条。

对于那些几年后偶然发现的人(就像我一样) ,我稍微调整了一下6502的方法,让进度条在增加的同时也在减少。在稍微多一点的情况下有用。感谢6502为一个伟大的工具!

基本上,唯一的区别是,每次调用进度(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()

一个更优雅的解决方案可能是:

def progress_bar(current, total, bar_length=20):
fraction = current / total


arrow = int(fraction * bar_length - 1) * '-' + '>'
padding = int(bar_length - len(arrow)) * ' '


ending = '\n' if current == total else '\r'


print(f'Progress: [{arrow}{padding}] {int(fraction*100)}%', end=ending)

currenttotal调用这个函数:

progress_bar(69, 100)

结果应该是

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

注:

巨蟒3中,你可以这样在同一行上打印:

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

特别有助于跟踪最新的更新和进展。

如果需要查看循环的进度,我还建议使用 tqdm 从这里。它将当前迭代和总迭代作为预期完成时间的进度条打印出来。非常有用而且迅速。为 python2和 python3工作。

阿拉文 · 沃古的例子中增加了一些功能:

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作为一个固定宽度的值。

对于两个循环和两倍于 progressBar()的使用,结果将是这样的:

progress bar animation

如果我们查看 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)

下面的代码将计数消息从0到137每0.3秒替换前一个数字。

到后台的符号数 = 位数。

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)

我写了这个一段时间前,真的很高兴与它。随时使用它。

它需要一个 indextotal和可选的 titlebar_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(),如果这是感兴趣的。

from time import sleep


max_val = 40


for done in range(max_val):
sleep(0.05)


undone = max_val - 1 - done
proc = (100 * done) // (max_val - 1)
print(f"\rProgress: [{('#' * done) + ('_' * undone)}] ({proc}%)", end='\r')


print("\nDone!")
Progress: [###################_____________________] (47%)
Progress: [########################################] (100%)
Done!