如何清空print函数的输出?

1586

我该如何强制Python的print函数将缓冲输出刷新到屏幕上?


另请参阅:如果目标是通常更改缓冲行为,请使用禁用输出缓冲。本问题是关于在特定print调用后显式刷新输出,尽管仍在缓冲输出。

对于重复关闭者:如果初学者正在询问有关尝试使输出立即出现而不使用结尾换行符的问题,请使用为什么没有结尾换行符时,终端上的打印输出不会立即显示?来关闭问题。当前问题不够好,因为提问者很可能没有概念缓冲或刷新;另一个问题旨在首先解释这些概念,而这个问题涉及技术细节。


13
对我而言,“python -u <script.py>” 可以正常工作(强制刷新,无缓存),无需修改脚本即可实现。 - Charlie Parker
1
请注意,该行为在IDE中出现了著名的错误。例如,PyCharm在调试控制台中可以正常工作,但在运行控制台中无法正常工作。您可能需要隔离问题存在于普通终端中。 - Charles Merriam
13个回答

1872
在Python 3中,print可以使用可选的flush参数:
print("Hello, World!", flush=True)

在Python 2中,调用print后执行:
import sys
sys.stdout.flush()

默认情况下,print 会将输出打印到sys.stdout(有关文件对象的详细信息请参阅文档)。


2
如果我使用 sys.stdout.flush(),是否可以避免使用 flush 关键字?我的文件中有很多打印语句,我不想改变它们,而且我希望我的文件始终刷新,并且不想每次都写 flush。我只想始终刷新。在文件顶部放置 sys.stdout.flush() 是否足够?(我正在使用 Python 3 及以上版本) - Charlie Parker
3
不,你需要在每次调用print时执行sys.stdout.flush()(或在Python 3中使用print(..., flush=True))。查看此答案以获取可能适合您的另一种解决方案。 - erobertc
5
在无需修改脚本的情况下,使用python -u <script.py>对我很有效。 - Charlie Parker
22
可能有点晚了,但如果您想让自己的打印输出始终像@Charlie Parker一样刷新,可以使用print = functools.partial(print, flush=True) - Nephanth
1
有时候在我的 Mac 上,Python 3.8.3 中的 flush=True 没有作用,当下一条消息是一个 logger 时。我不得不添加 sys.stdout.flush()。 - Eric H.
显示剩余5条评论

434

运行 python -h 命令, 我看到一个命令行选项:

-u : 无缓冲二进制标准输出和标准错误; 同样适用于 PYTHONUNBUFFERED=x。 有关 '-u' 内部缓冲相关的详细信息,请参阅 man 手册。

这里是相关文档


13
如果您在Linux / Unix平台上运行它,可以在解释器命令行中添加“-u”选项(脚本文件的第一行),将第一行从(类似于)“#! /usr/bin/python3”更改为“#! /usr/bin/python3 -u”,现在当您运行脚本时(例如,./my_script.py),会自动添加-u选项。 - James Stevens
-u 的功能如预期一样正常(Y) - younes zeboudj
-u 的功能如预期一样正常(Y) - undefined

342

自 Python 3.3 开始,您可以通过将 "flush" 关键字参数设置为 true 来强制普通的 print() 函数刷新,而无需使用 sys.stdout.flush();来自文档

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

将对象打印到文件流中,由 sep 分隔并以 end 结尾。如果存在,则必须将 sep、end 和 file 给出为关键字参数。

所有非关键字参数都像 str() 一样转换为字符串,并由 sep 分隔,然后跟随 end。sep 和 end 都必须是字符串;它们还可以是 None,这意味着使用默认值。如果没有给出对象,则 print() 将只写入 end。

文件参数必须是具有write(string)方法的对象;如果不存在或为 None,则将使用 sys.stdout。输出是否缓冲通常由文件确定,但如果 flush 关键字参数为 true,则会强制刷新流。


1
如果我执行 sys.stdout.flush(),我能避免使用 flush 关键字吗?我的文件中有很多打印语句,我不想改变它们,而且我希望我的文件总是刷新,并且我不想每次都写。我只想要一直刷新。在顶部放置 sys.stdout.flush() 是否足够?(我正在使用 Python 3 及以上版本) - Charlie Parker
顺便问一下,import sys sys.stdout.flush() 在 Python3 中还有效吗?我不想修改整个脚本来强制刷新。 - Charlie Parker

270

如何刷新Python print的输出?

我建议以下五种方式:

  • 在 Python 3 中,调用 print(..., flush=True)(Python 2 的 print 函数不提供 flush 参数,print 语句也没有类似的参数)。
  • 在输出文件上调用 file.flush()(可以将 Python 2 的 print 函数包装起来实现),例如 sys.stdout
  • 对于模块中的每个 print 函数调用,应用一个部分函数:
    print = partial(print, flush=True) 应用于模块全局。
  • 通过传递给解释器命令的标志(-u)将其应用于进程。
  • 对于您的环境中的每个 Python 进程都应用此方法,使用 PYTHONUNBUFFERED=TRUE(取消设置该变量以撤消此操作)。

Python 3.3+

在使用 Python 3.3 或更高版本时,只需将 flush=True 作为关键字参数提供给 print 函数即可:

print('foo', flush=True) 

Python 2(或 < 3.3)

他们没有将flush参数回溯到Python 2.7。因此,如果您使用的是Python 2(或小于3.3),并且想要与2和3兼容的代码,我建议使用以下兼容性代码。(请注意,__future__导入必须位于/非常“靠近模块顶部”):

from __future__ import print_function
import sys

if sys.version_info[:2] < (3, 3):
    old_print = print
    def print(*args, **kwargs):
        flush = kwargs.pop('flush', False)
        old_print(*args, **kwargs)
        if flush:
            file = kwargs.get('file', sys.stdout)
            # Why might file=None? IDK, but it works for print(i, file=None)
            file.flush() if file is not None else sys.stdout.flush()

上述兼容性代码将涵盖大多数用途,但为了更全面的处理,请参阅six模块

或者,您也可以在打印后调用file.flush(),例如,在Python 2中使用print语句:

import sys
print 'delayed output'
sys.stdout.flush()

将一个模块的默认设置更改为flush=True

您可以通过在模块的全局范围内使用functools.partial来更改print函数的默认设置:

import functools
print = functools.partial(print, flush=True)

如果您查看我们的新部分函数,至少在Python 3中:

>>> print = functools.partial(print, flush=True)
>>> print
functools.partial(<built-in function print>, flush=True)

我们可以看到它的工作方式与正常相同:

>>> print('foo')
foo

而且我们实际上可以覆盖新的默认值:

>>> print('foo', flush=False)
foo

请注意,这只会改变当前的全局作用域,因为当前全局范围内的打印名称将覆盖内置的print函数(或者在Python 2中使用兼容函数时,在当前的全局范围内取消引用此函数)。

如果您想在函数内而不是在模块的全局范围内执行此操作,则应该给它一个不同的名称,例如:

def foo():
    printf = functools.partial(print, flush=True)
    printf('print stuff like this')

如果你在函数中将其声明为全局变量,那么你正在改变模块的全局命名空间,所以你应该将其放在全局命名空间中,除非这种特定的行为恰好是你想要的。

更改进程的默认设置

我认为在这里最好的选择是使用-u标志来获取无缓冲输出。

$ python -u script.py
或者
$ python -um package.module

根据文档

强制stdin,stdout和stderr完全不带缓冲区。 在需要的系统上,还将stdin,stdout和stderr置于二进制模式。

请注意,file.readlines()和File Objects(对于sys.stdin中的line)中存在内部缓冲区,此选项不受影响。 要解决此问题,您需要在while 1:循环内使用file.readline()。

更改 shell 操作环境的默认值

如果您将环境变量设置为非空字符串,则可以在环境中的所有Python进程或继承自该环境的环境中获得此行为:

例如,在Linux或OSX中:

$ export PYTHONUNBUFFERED=TRUE

对于Windows操作系统:

C:\SET PYTHONUNBUFFERED=TRUE

来自文档

PYTHONUNBUFFERED

如果将其设置为非空字符串,则相当于指定-u选项。


附录

以下是Python 2.7.12的print函数帮助文档 - 请注意,没有 flush参数:

>>> from __future__ import print_function
>>> help(print)
print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file: a file-like object (stream); defaults to the current sys.stdout.
    sep:  string inserted between values, default a space.
    end:  string appended after the last value, default a newline.

2
对于从较低版本的Python迁移过来的好奇者:__future__版本不包括flush,因为“flush参数是在Python 3.3中添加的(在通过未来导入将print()回溯到2.7之后)”https://bugs.python.org/issue28458 - Oliver
这应该是被接受的答案。提供解决方案和大量信息。 - TheTechRobo the Nerd
如果我执行 sys.stdout.flush(),我就不必加上 flush 关键字了吗?我的文件中有很多打印语句,我不想改变它们,而且我希望我的文件始终刷新,而且我也不想每次都写这个关键字。我只是想始终刷新。在顶部放置sys.stdout.flush()是否足够?(我正在使用 Python 3 或更高版本) - Charlie Parker
不可以,但你可以在模块顶部(例如在导入之后)添加类似于 import functools; print = functools.partial(print, flush=True) 的代码,并将其分配给名称 print 以实现进程范围的适用性。 - Russia Must Remove Putin
类似于 import functools; print2 = functools.partial(print, flush=True); builtins.print=print2 吗?@AaronHall - Charlie Parker
顺便问一下,import sys sys.stdout.flush() 在 Python3 中还有效吗?我不想修改整个脚本来强制刷新。 - Charlie Parker

72

另外,正如这篇博客文章中所建议的那样,可以以无缓冲模式重新打开sys.stdout

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

stdout.writeprint操作会在执行后自动刷新。


3
在Ubuntu 12.04中使用Python 2.7,这会导致出现“UnsupportedOperation: IOStream has no fileno.”的错误。 - drevicko
4
哎呀,Python 3 发现了。它不会让我执行这段代码! - EKons
1
我对这个习惯用法感到困惑。在你这样做之后,现在不是有两个类似于文件的对象(原始的sys.stdout和新的sys.stdout),它们都认为自己“拥有”fileno吗?那不好,对吧? - Don Hatch
如果您查看文档,buffering=0 只在二进制模式下起作用。buffering 是一个可选的整数,用于设置缓冲策略。传递 0 来关闭缓冲(仅在二进制模式下允许使用),传递 1 来选择行缓冲(仅在文本模式下可用),传递一个大于 1 的整数来指示固定大小块缓冲区的字节数。 - N4ppeL

70

随着Python 3.x的发布,print()函数已得到扩展:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

所以,你只需要这样做:

print("Visiting toilet", flush=True)

Python文档条目



2
它与Eugene Sajine的回答有何不同? - Peter Mortensen
1
@PeterMortensen 这个答案有点幽默,而另一个则没有。 - SethMMorton

40

使用-u命令行选项可以起作用,但有点笨拙。这意味着如果用户不使用-u选项调用脚本,则该程序可能会出现错误行为。我通常会使用自定义的stdout,像这样:

class flushfile:
  def __init__(self, f):
    self.f = f

  def write(self, x):
    self.f.write(x)
    self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

现在,所有使用 sys.stdout 隐式调用的 print 语句将自动执行 flush


5
我建议不要从文件继承,然后通过添加“def getattr(self,name): return object.getattribute(self.f, name)”来委托给标准输出。 - diedthreetimes
2
没有由@diedthreetimes评论建议的更改,我会得到“ValueError:在关闭的文件上进行I/O操作”。 - blueFast

20

使用无缓冲文件:

f = open('xyz.log', 'a', 0)

或者

sys.stdout = open('out.log', 'a', 0)

4
他不想创建无缓冲文件;他想让现有的标准输出(stdout)(重定向到控制台、终端或其他地方:这部分不能更改)变成无缓冲的。 - blueFast

18

在Python 3中,您可以将print函数的默认设置覆盖为flush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)

3
考虑到其他高质量回答的存在,这个回答似乎有些简略了。您可能需要对它进行补充。 - Semicolons and Duct Tape

16

丹的想法并不完全有效:

#!/usr/bin/env python
class flushfile(file):
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

print "foo"

结果:
Traceback (most recent call last):
  File "./passpersist.py", line 12, in <module>
    print "foo"
ValueError: I/O operation on closed file

我认为问题在于它继承了文件类,实际上这并不是必需的。根据sys.stdout的文档:

stdout和stderr不一定是内置的文件对象:只要具有接受字符串参数的write()方法,任何对象都可接受。

因此更改为

class flushfile(file):

to

class flushfile(object):

使其正常工作。


20
不投票,因为这是@Dan的解决方案…(你应该评论Dan的帖子而不是复制他的解决方案) - gecco

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