问题:如何在python中将以前的打印内容覆盖到stdout?

如果我有以下代码:

for x in range(10):
     print x

我会得到的输出

1
2
etc..

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

If I had the following code:

for x in range(10):
     print x

I would get the output of

1
2
etc..

What I would like to do is instead of printing a newline, I want to replace the previous value and overwrite it with the new value on the same line.


回答 0

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

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

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

更新资料

既然Python 2是EOL,Python 3的答案就更有意义了。对于Python 3.5及更早版本:

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

在Python 3.6及更高版本中,f字符串的读取效果更好:

for x in range(10):
    print(f'{x}\r', end="")
print()

Simple Version

One way is to use the carriage return ('\r') character to return to the start of the line without advancing to the next line.

Python 3

for x in range(10):
    print(x, end='\r')
print()

Python 2.7 forward compatible

from __future__ import print_function
for x in range(10):
    print(x, end='\r')
print()

Python 2.7

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

Python 2.0-2.6

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

In the latter two (Python 2-only) cases, the comma at the end of the print statement tells it not to go to the next line. The last print statement advances to the next line so your prompt won’t overwrite your final output.

Line Cleaning

If you can’t guarantee that the new line of text is not shorter than the existing line, then you just need to add a “clear to end of line” escape sequence, '\x1b[1K' ('\x1b' = ESC):

for x in range(75):
    print(‘*’ * (75 - x), x, end='\x1b[1K\r')
print()

回答 1

由于我是通过Google结束的,但是正在使用Python 3,因此这是在Python 3中的工作方式:

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

相关答案在这里:如何在打印语句后取消换行符?

Since I ended up here via Google but am using Python 3, here’s how this would work in Python 3:

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

Related answer here: How can I suppress the newline after a print statement?


回答 2

@Mike DeSimone的答案可能在大多数时间都有效。但…

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

-> 1bc

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

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

如果POSIX支持足以满足您的需求,则以下内容将清除当前行并将光标留在其开头:

print '\x1b[2K\r',

它使用ANSI转义码清除端子线。有关更多信息,请参见Wikipedia此精彩演讲

旧答案

我发现的(不太好)解决方案如下所示:

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

-> 1

优点之一是它也可以在Windows上运行。

@Mike DeSimone answer will probably work most of the time. But…

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

-> 1bc

This is because the '\r' only goes back to the beginning of the line but doesn’t clear the output.

EDIT: Better solution (than my old proposal below)

If POSIX support is enough for you, the following would clear the current line and leave the cursor at its beginning:

print '\x1b[2K\r',

It uses ANSI escape code to clear the terminal line. More info can be found in wikipedia and in this great talk.

Old answer

The (not so good) solution I’ve found looks like this:

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

-> 1

One advantage is that it will work on windows too.


回答 3

在访问此线程之前,我有同样的问题。对我来说,sys.stdout.write仅在我正确刷新缓冲区时才起作用,即

for x in range(10):
    sys.stdout.write('\r'+str(x))
    sys.stdout.flush()

不冲洗,结果仅在脚本的末尾打印

I had the same question before visiting this thread. For me the sys.stdout.write worked only if I properly flush the buffer i.e.

for x in range(10):
    sys.stdout.write('\r'+str(x))
    sys.stdout.flush()

Without flushing, the result is printed only at the end out the script


回答 4

取消换行并打印\r

print 1,
print '\r2'

或写到标准输出:

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

Suppress the newline and print \r.

print 1,
print '\r2'

or write to stdout:

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

回答 5

试试这个:

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

Try this:

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

It worked for me. The end="\r" part is making it overwrite the previous line.

WARNING!

If you print out hi, then print out hello using \r, you’ll get hillo because the output wrote over the previous two letters. If you print out hi with spaces (which don’t show up here), then it will output hi. To fix this, print out spaces using \r.


回答 6

我无法在此页面上找到任何可用于IPython的解决方案,但对@ Mike-Desimone的解决方案进行了一些改动即可完成工作:与其以回车符结尾而不是以回车符开头

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

此外,此方法不需要第二个print语句。

I couldn’t get any of the solutions on this page to work for IPython, but a slight variation on @Mike-Desimone’s solution did the job: instead of terminating the line with the carriage return, start the line with the carriage return:

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

Additionally, this approach doesn’t require the second print statement.


回答 7

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

time.sleep(0.5)用于显示如何清除先前的输出,并在打印消息开始时“ \ r”打印新的输出,它将在新输出之前擦除先前的输出。

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

time.sleep(0.5) is to show how previous output is erased and new output is printed “\r” when its at the start of print message , it gonna erase previous output before new output.


回答 8

这适用于Windows和python 3.6

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

This works on Windows and python 3.6

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

回答 9

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

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

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%

The accepted answer is not perfect. The line that was printed first will stay there and if your second print does not cover the entire new line, you will end up with garbage text.

To illustrate the problem save this code as a script and run it (or just take a look):

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

The output will look something like this:

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

What works for me is to clear the line before leaving a permanent print. Feel free to adjust to your specific problem:

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

And now it prints as expected:

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

回答 10

这是@ 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)

Here’s a cleaner, more “plug-and-play”, version of @Nagasaki45’s answer. Unlike many other answers here, it works properly with strings of different lengths. It achieves this by clearing the line with just as many spaces as the length of the last line printed print. Will also work on 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

Usage

Simply use it like this:

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

This small test shows that lines get cleared properly, even for different lengths:

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

回答 11

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

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

I’m a bit surprised nobody is using the backspace character. Here’s one that uses it.

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

回答 12

(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

(Python3) This is what worked for me. If you just use the \010 then it will leave characters, so I tweaked it a bit to make sure it’s overwriting what was there. This also allows you to have something before the first print item and only removed the length of the item.

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

回答 13

根据先前的答案再回答一个。

pbar.py的内容:import sys,shutil,datetime

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)

One more answer based on the prevous answers.

Content of pbar.py: import sys, shutil, datetime

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

Usage of script:

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)

回答 14

这是我的解决方案!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

Here’s my solution! Windows 10, Python 3.7.1

I’m not sure why this code works, but it completely erases the original line. I compiled it from the previous answers. The other answers would just return the line to the beginning, but if you had a shorter line afterwards, it would look messed up like hello turns into 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)

Output – Each line will be rewritten without any old text showing:

SCRAPING COMPLETE: selenagomez

Next line (rewritten completely on same line):

SCRAPING COMPLETE: beyonce

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。