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

How to overwrite the previous print to stdout in python?

如果我有以下代码:

1
2
for x in range(10):
     print x

我会得到的输出

1
2
3
1
2
etc..

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


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

1
2
3
4
for x in range(10):
    print '{0}
'
.format(x),
print

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


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

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

相关答案:如何在打印声明后抑制换行符?


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

1
2
3
4
5
for x in ['abc', 1]:
    print '{}
'
.format(x),

-> 1bc

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

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

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

1
2
print '\x1b[2K
'
,

它使用ANSI转义码来清除终端线。更多信息可以在维基百科和这个精彩的演讲中找到。

老答案

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

1
2
3
4
5
6
7
8
9
last_x = ''
for x in ['abc', 1]:
    print ' ' * len(str(last_x)) + '
'
,
    print '{}
'
.format(x),
    last_x = x

-> 1

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


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

1
2
3
4
for x in range(10):
    sys.stdout.write('
'
+str(x))
    sys.stdout.flush()

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


取消换行并打印

1
2
3
print 1,
print '
2'

或者写信给stdout:

1
2
3
sys.stdout.write('1')
sys.stdout.write('
2'
)


我无法让这个页面上的任何解决方案适用于IPython,但是@ Mike-Desimone的解决方案稍有不同就完成了这项工作:不是使用回车符终止该行,而是使用回车符开始行:

1
2
3
for x in range(10):
    print '
{0}'
.format(x),

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


试试这个:

1
2
3
4
5
6
7
8
import time
while True:
    print("Hi", end="
"
)
    time.sleep(1)
    print("Bob", end="
"
)
    time.sleep(1)

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

警告!

如果你打印hi,然后使用
打印hello,你将得到hillo,因为输出写了前两个字母。如果用空格打印hi(这里没有显示),则输出hi。要解决此问题,请使用
打印空格。


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

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


接受的答案并不完美。首先打印的行将保留在那里,如果您的第二个打印不覆盖整个新行,您将最终得到垃圾文本。

为了说明问题,将此代码保存为脚本并运行它(或者只是看看):

1
2
3
4
5
6
7
8
9
import time

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

输出看起来像这样:

1
2
3
4
Progress 0.0%%
Progress 1.0%%
Progress 2.0%%
Progress 3.0%%

对我有用的是在离开永久印刷品之前清除线条。随意调整您的具体问题:

1
2
3
4
5
6
7
8
9
10
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="
"
)
        time.sleep(0.01)
    print(ERASE_LINE +"Progress {:2.1%}".format(i / 100)) # clear the line first

现在按预期打印:

1
2
3
4
Progress 0.0%
Progress 1.0%
Progress 2.0%
Progress 3.0%

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

1
2
3
4
5
6
7
8
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='
'
)
    print(msg, end='
'
)
    sys.stdout.flush()  # Some say they needed this, I didn't.
    print_statusline.last_msg = msg

用法

只需使用它:

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

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

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


这适用于Windows和python 3.6

1
2
3
4
5
import time
for x in range(10):
    time.sleep(0.5)
    print(str(x)+'
'
,end='')


(Python3)这对我有用。 如果你只是使用 010然后它将留下字符,所以我稍微调整它以确保它覆盖那里的东西。 这也允许您在第一个打印项目之前拥有一些东西,并且只删除项目的长度。

1
2
3
4
5
6
7
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

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

1
2
3
for i in range(10):
    print(i*'.', end='
'
)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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')


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

我不确定为什么这段代码有效,但它完全抹去了原来的行。 我从以前的答案中编译了它。 其他答案只会将线条返回到开头,但如果之后有一条较短的线条,它看起来会像hello变成byelo一样混乱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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+'
'
)
    print(msg, end='
'
)

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

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

1
SCRAPING COMPLETE: selenagomez

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

1
SCRAPING COMPLETE: beyonce

这里有一个简单的代码,对您有用!

1
2
3
4
5
6
7
8
import sys
import time

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