如何在python中覆盖以前的打印到stdout?

时间:2011-03-24 12:50:06

标签: python

如果我有以下代码:

for x in range(10):
     print x

我会得到

的输出
1
2
etc..

我想要做的是不是打印换行符,而是要替换之前的值并用同一行上的新值覆盖它。

19 个答案:

答案 0 :(得分:99)

一种方法是使用回车符('\r')字符返回到行的开头,而不会前进到下一行:

for x in range(10):
    print '{0}\r'.format(x),
print

print语句末尾的逗号告诉它不要转到下一行。最后一个打印语句前进到下一行,因此您的提示不会覆盖最终输出。

答案 1 :(得分:80)

由于我最终通过Google访问,但我使用的是Python 3,以及这在Python 3中是如何工作的:

for x in range(10):
    print("Progress {:2.1%}".format(x / 10), end="\r")

相关答案:How can I suppress the newline after a print statement?

答案 2 :(得分:24)

@Mike DeSimone的回答可能大部分时间都有效。但...

for x in ['abc', 1]:
    print '{}\r'.format(x),

-> 1bc

这是因为'\r'只会返回到行的开头,但不会清除输出。

编辑:更好的解决方案(比我下面的旧提议)

如果POSIX支持对您来说足够了,以下将清除当前行并将光标留在其开头:

print '\x1b[2K\r',

它使用ANSI转义码来清除终端线。可以在in wikipediathis great talk中找到更多信息。

旧答案

我发现的(不那么好)解决方案看起来像这样:

last_x = ''
for x in ['abc', 1]:
    print ' ' * len(str(last_x)) + '\r',
    print '{}\r'.format(x),
    last_x = x

-> 1

一个优点是它也适用于Windows。

答案 3 :(得分:22)

在访问此主题之前,我遇到了同样的问题。对我来说,sys.stdout.write只有在我正确刷新缓冲区时才有效。

    function addRow(frm) {    
        rowNum ++;
        for(i; i<10; i++){
            var row = '<div id="itemRows"><label for="file_01">File 01</label><input type="file"  name="file[]" multiple>';
            jQuery('#itemRows').append(row);
        }
    }

如果没有刷新,结果只会在脚本的末尾打印

答案 4 :(得分:17)

取消换行并打印\r

print 1,
print '\r2'

或写入stdout:

sys.stdout.write('1')
sys.stdout.write('\r2')

答案 5 :(得分:7)

我无法在此页面上获得 IPython 的任何解决方案,但是@ Mike-Desimone的解决方案稍有不同就完成了这项工作:而不是终止带回车符的行,开始带回车符的行:

for x in range(10):
    print '\r{0}'.format(x),

此外,这种方法不需要第二个打印声明。

答案 6 :(得分:6)

试试这个:

import time
while True:
    print("Hi ", end="\r")
    time.sleep(1)
    print("Bob", end="\r")
    time.sleep(1)

它对我有用。 end="\r"部分正在覆盖前一行。

警告!

如果您打印hi,然后使用hello打印\r,您将获得hillo,因为输出会写入前两个字母。如果您使用空格打印hi(此处未显示),则会输出hi。要解决此问题,请使用\r打印空格。

答案 7 :(得分:4)

for x in range(10):
    time.sleep(0.5) # shows how its working
    print("\r {}".format(x), end="")

time.sleep(0.5)用于显示如何擦除先前的输出并打印新输出 &#34; \ R&#34;当它在打印消息开始时,它将在新输出之前擦除先前的输出。

答案 8 :(得分:4)

接受的答案不是完美。首先打印的行将保留在该行中,如果第二次打印没有覆盖整个新行,则最终将显示垃圾文本。

为说明问题,请将此代码另存为脚本并运行(或只是看一下):

import time

n = 100
for i in range(100):
    for j in range(100):
        print("Progress {:2.1%}".format(j / 100), end="\r")
        time.sleep(0.01)
    print("Progress {:2.1%}".format(i / 100))

输出将如下所示:

Progress 0.0%%
Progress 1.0%%
Progress 2.0%%
Progress 3.0%%

对我而言,有效的方法是在留下永久打印之前清除线条。随时根据您的具体问题进行调整:

import time

ERASE_LINE = '\x1b[2K' # erase line command
n = 100
for i in range(100):
    for j in range(100):
        print("Progress {:2.1%}".format(j / 100), end="\r")
        time.sleep(0.01)
    print(ERASE_LINE + "Progress {:2.1%}".format(i / 100)) # clear the line first

现在它可以按预期打印:

Progress 0.0%
Progress 1.0%
Progress 2.0%
Progress 3.0%

答案 9 :(得分:3)

这适用于Windows和python 3.6

import time
for x in range(10):
    time.sleep(0.5)
    print(str(x)+'\r',end='')

答案 10 :(得分:2)

这是@ Nagasaki45的答案更清洁,更“即插即用”的版本。与此处的许多其他答案不同,它适用于不同长度的字符串。它通过使用与最后一行打印的长度一样多的空格清除行来实现此目的。也适用于Windows。

def print_statusline(msg: str):
    last_msg_length = len(print_statusline.last_msg) if hasattr(print_statusline, 'last_msg') else 0
    print(' ' * last_msg_length, end='\r')
    print(msg, end='\r')
    sys.stdout.flush()  # Some say they needed this, I didn't.
    print_statusline.last_msg = msg

用法

只需像这样使用它:

for msg in ["Initializing...", "Initialization successful!"]:
    print_statusline(msg)
    time.sleep(1)

这个小测试表明线条可以正确清除,即使长度不同:

for i in range(9, 0, -1):
    print_statusline("{}".format(i) * i)
    time.sleep(0.5)

答案 11 :(得分:2)

(Python3)这对我有用。如果只使用\ 010,它将留下字符,因此我对其进行了一些调整,以确保它覆盖了那里的内容。这也使您可以在第一个打印项目之前放一些东西,而只删除该项目的长度。

print("Here are some strings: ", end="")
items = ["abcd", "abcdef", "defqrs", "lmnop", "xyz"]
for item in items:
    print(item, end="")
    for i in range(len(item)): # only moving back the length of the item
        print("\010 \010", end="") # the trick!
        time.sleep(0.2) # so you can see what it's doing

答案 12 :(得分:2)

我使用以下方法创建了一个加载器:

$('td.coloured').css('background-color','#8F8F8F').toggleClass('coloured');

答案 13 :(得分:1)

我有点惊讶没有人使用退格字符。这是使用它的人。

import sys
import time

secs = 1000

while True:
    time.sleep(1)  #wait for a full second to pass before assigning a second
    secs += 1  #acknowledge a second has passed

    sys.stdout.write(str(secs))

    for i in range(len(str(secs))):
        sys.stdout.write('\b')

答案 14 :(得分:1)

最好覆盖整行,否则,如果新行较短,则新行将与旧行混合。

import time, os
for s in ['overwrite!', 'the!', 'whole!', 'line!']:
    print(s.ljust(os.get_terminal_size().columns - 1), end="\r")
    time.sleep(1)

必须在Windows上使用columns - 1

答案 15 :(得分:0)

这是我的解决方案! Windows 10,Python 3.7.1

我不确定该代码为什么起作用,但是它会完全删除原始行。我根据先前的答案进行了编译。其他答案只是将行返回到开头,但是如果之后的行较短,它将看起来像是hello变成byelo时那样混乱。

import sys
#include ctypes if you're on Windows
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
#end ctypes

def clearline(msg):
    CURSOR_UP_ONE = '\033[K'
    ERASE_LINE = '\x1b[2K'
    sys.stdout.write(CURSOR_UP_ONE)
    sys.stdout.write(ERASE_LINE+'\r')
    print(msg, end='\r')

#example
ig_usernames = ['beyonce','selenagomez']
for name in ig_usernames:
    clearline("SCRAPING COMPLETE: "+ name)

输出-每行将被重写,而不会显示任何旧文本:

SCRAPING COMPLETE: selenagomez

下一行(完全在同一行上重写):

SCRAPING COMPLETE: beyonce

答案 16 :(得分:0)

基于先前的答案又一个答案。

pbar.py的内容:     导入系统,关机,日期时间

last_line_is_progress_bar=False


def print2(print_string):
    global last_line_is_progress_bar
    if last_line_is_progress_bar:
        _delete_last_line()
        last_line_is_progress_bar=False
    print(print_string)


def _delete_last_line():
    sys.stdout.write('\b\b\r')
    sys.stdout.write(' '*shutil.get_terminal_size((80, 20)).columns)
    sys.stdout.write('\b\r')
    sys.stdout.flush()


def update_progress_bar(current, total):
    global last_line_is_progress_bar
    last_line_is_progress_bar=True

    completed_percentage = round(current / (total / 100))
    current_time=datetime.datetime.now().strftime('%m/%d/%Y-%H:%M:%S')
    overhead_length = len(current_time+str(current))+13
    console_width = shutil.get_terminal_size((80, 20)).columns - overhead_length
    completed_width = round(console_width * completed_percentage / 100)
    not_completed_width = console_width - completed_width
    sys.stdout.write('\b\b\r')

    sys.stdout.write('{}> [{}{}] {} - {}% '.format(current_time, '#'*completed_width, '-'*not_completed_width, current,
                                        completed_percentage),)
    sys.stdout.flush()

脚本的用法:

import time
from pbar import update_progress_bar, print2


update_progress_bar(45,200)
time.sleep(1)

update_progress_bar(70,200)
time.sleep(1)

update_progress_bar(100,200)
time.sleep(1)


update_progress_bar(130,200)
time.sleep(1)

print2('some text that will re-place current progress bar')
time.sleep(1)

update_progress_bar(111,200)
time.sleep(1)

print('\n') # without \n next line will be attached to the end of the progress bar
print('built in print function that will push progress bar one line up')
time.sleep(1)

update_progress_bar(111,200)
time.sleep(1)

答案 17 :(得分:0)

这对我有用,在 Windows 中的 Spyder 中使用 Python 3.7.9:

from IPython.display import clear_output
from time import sleep

def print_and_overwrite(text):
    '''Remember to add print() after the last print that you want to overwrite.'''
    clear_output(wait=True)
    print(text, end='\r')

for i in range(15):
    #I print the results backwards (from 15 to 1), to test shorter strings
    message = "Iteration %d out of 15" %(15-i)
    print_and_overwrite(message)
    sleep(0.5)

print() #This stops the overwriting
print("This will be on a new line")

答案 18 :(得分:-2)

这是一个对你有用的简单代码!

import sys
import time

for i in range(10):
    sys.stdout.write("\r" + i)
    sys.stdout.flush()
    time.sleep(1)