为什么在没有换行符的情况下,打印输出不会立即显示在终端上?

22
我有一个用Python编写的脚本,用于进行模拟。每次迭代的运行时间长短不一,因此我在每个循环后打印一个.,以便监视它的运行速度和在脚本运行时通过for语句走了多远。因此,代码的结构大致如下:
for step in steps:
    run_simulation(step)
    # Python 3.x version:
    print('.', end='')
    # for Python 2.x:
    # print '.',

然而,当我运行代码时,这些点并没有一个接一个的出现。相反,当循环结束时,所有的点都会一次性打印出来,这使得所有的努力都失去了意义。如何在代码运行时以内联方式打印这些点?
这个问题也可能发生在迭代从另一个进程提供的数据并尝试打印结果时,例如回显来自Electron应用程序的输入。请参见Python not printing output

5
很可能是行缓冲的问题。尝试在打印内容后发出sys.stdout.flush()命令。如果这解决了你的问题,那么缓冲确实是你的问题所在。 - Lukas Graf
1
你也可以将stdout设置为无缓冲...但通常做这样的事情的方法正是@LukasGraf所建议的。除了你可能想要使用sys.stdout.write('.')而不是print '.',。首先,print会在点之间给你空格。其次,它理论上允许在stdout所做的任何缓冲之上进行自己的缓冲(尽管CPython不会这样做,我也不知道有哪个实现会这样做)。 - abarnert
是的,它起作用了。谢谢!不过我想知道是否有更好的方法来做这件事,而不仅仅是打印点... - LWZ
我也推荐使用sys.stdout.write。如果需要绕过问题(例如无法修改源代码),可以尝试按照这里所述使用Python的-u选项来运行。 - mtik00
1
尽管你的问题是关于“为什么”,但显然的后续问题将是“我该如何关闭缓冲?”,因此我投票将其标记为重复。 - Lukas Graf
显示剩余2条评论
1个回答

25

问题

Python程序的输出默认是缓冲的,以提高性能。终端程序与您的代码是一个独立的程序,存储文本并一次性传递它比单独要求终端程序显示每个符号更有效。

由于终端程序通常用于交互使用,输入和输出按行逐步进行(例如,预计用户击键Enter以指示单个输入项的结束),因此默认情况下将输出一行一行地进行缓冲。

因此,如果没有打印换行符, print 函数(在3.x中; print 语句在2.x中)将简单地将文本添加到缓冲区中,而不会显示任何内容。

其他输出方式

偶尔会有人尝试通过直接使用标准输出流来从Python程序中输出:

import sys
sys.stdout.write('test')

如果输出没有以换行符结束,它将停留在缓冲区中直到被刷新,这个问题仍然存在。

修复问题

对于单个print

我们可以在打印后显式地刷新输出

在3.x中,print函数具有flush关键字参数,可以直接解决该问题:

for _ in range(10):
    print('.', end=' ', flush=True)
    time.sleep(.2)  # or other time-consuming work

在2.x中,print语句不提供此功能。相反,要显式地刷新流,请使用其.flush方法。标准输出流(默认情况下,文本在print时进入该流)由sys标准库模块提供,并命名为stdout。因此,代码看起来会像这样:

for _ in range(10):
    print '.',
    sys.stdout.flush()
    time.sleep(.2)  # or other time-consuming work

对于多次 print

与其在每次print后刷新(或之后决定哪些需要刷新),更好的方法是可以完全禁用输出行缓冲。有许多方法可以实现这一点,因此请参考链接的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接