如何强制Python的print函数将缓冲输出刷新到屏幕?
另请参阅:如果目标是更改缓冲行为,则禁用输出缓冲。这个问题是关于在特定打印调用后显式刷新输出,即使输出仍在缓冲。
对于重复的闭包:如果初学者问了一个问题,试图在结尾处不使用换行符的情况下立即显示输出,请改用“当结尾处没有换行符时,为什么打印输出不立即显示在终端中?”?结束问题。目前的问题还不够好,因为提问者可能没有缓冲或冲洗的概念;另一个问题旨在首先解释这些概念,而这个问题是关于技术细节的。
如何强制Python的print函数将缓冲输出刷新到屏幕?
另请参阅:如果目标是更改缓冲行为,则禁用输出缓冲。这个问题是关于在特定打印调用后显式刷新输出,即使输出仍在缓冲。
对于重复的闭包:如果初学者问了一个问题,试图在结尾处不使用换行符的情况下立即显示输出,请改用“当结尾处没有换行符时,为什么打印输出不立即显示在终端中?”?结束问题。目前的问题还不够好,因为提问者可能没有缓冲或冲洗的概念;另一个问题旨在首先解释这些概念,而这个问题是关于技术细节的。
当前回答
从Python 3.3开始,您可以强制普通的print()函数刷新,而无需使用sys.stdout.flush();只需将“flush”关键字参数设置为true。根据文档:
打印(*对象,sep=“”,end=“\n”,file=sys.stdout,flush=False)将对象打印到流文件中,以sep分隔,后跟end。sep、end和file(如果存在)必须作为关键字参数提供。所有非关键字参数都被转换为字符串,如str()所做,并被写入流中,以sep分隔,后跟end。sep和end都必须是字符串;它们也可以是None,这意味着使用默认值。如果没有给定对象,print()将只写结束。file参数必须是具有write(string)方法的对象;如果不存在或无,将使用sys.stdout。输出是否缓冲通常由文件决定,但如果flush关键字参数为true,则强制刷新流。
其他回答
在Python 3中,print可以采用可选的flush参数:
print("Hello, World!", flush=True)
在Python 2中,调用print后,请执行以下操作:
import sys
sys.stdout.flush()
默认情况下,打印到sys.stdout(有关文件对象的详细信息,请参阅文档)。
丹的想法不太奏效:
#!/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
我认为问题是它继承自file类,这实际上是不必要的。根据sys.stdout的文档:
stdout和stderr不必内置文件对象:可以接受任何对象只要它有write()方法这需要一个字符串参数。
所以改变
class flushfile(file):
to
class flushfile(object):
使其工作正常。
如何刷新Python打印的输出?
我建议五种方法:
在Python 3中,调用print(…,flush=True)(flush参数在Python 2的print函数中不可用,print语句也没有类似的参数)。在输出文件上调用file.flush()(我们可以包装python2的打印函数来实现这一点),例如sys.stdout将此应用于具有部分函数的模块中的每个打印函数调用,print=局部(print,flush=True)应用于模块全局。通过传递给解释器命令的标志(-u)将此应用于进程使用PYTHONNBUFFERED=TRUE将此应用于环境中的每个python进程(并取消设置变量以撤消此操作)。
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()
上述兼容性代码将涵盖大多数用途,但要获得更彻底的处理,请参阅六个模块。
或者,您可以在打印后调用file.flush(),例如,使用Python 2中的print语句:
import sys
print 'delayed output'
sys.stdout.flush()
将一个模块中的默认值更改为flush=True
您可以通过在模块的全局范围上使用functools.partial来更改打印函数的默认值:
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
再次注意,这只会更改当前全局范围,因为当前全局范围上的打印名称将覆盖内置打印函数(或取消引用兼容函数,如果在Python 2中使用兼容函数,则在当前全局范围内)。
如果要在函数内部而不是在模块的全局范围内执行此操作,则应为其指定不同的名称,例如:
def foo():
printf = functools.partial(print, flush=True)
printf('print stuff like this')
如果您在函数中声明它是全局的,那么您将在模块的全局命名空间中更改它,因此您应该将它放在全局命名空间中,除非特定行为正是您想要的。
更改流程的默认值
我认为这里最好的选择是使用-u标志来获得无缓冲的输出。
$ python -u script.py
or
$ python -um package.module
从文档中:
强制完全取消缓冲stdin、stdout和stderr。在重要的系统上,也将stdin、stdout和stderr设置为二进制模式。请注意,file.readlines()和file Objects(用于sys.stdin中的行)中存在内部缓冲,不受此选项的影响。要解决这个问题,您需要在while 1:循环中使用file.readline()。
更改shell操作环境的默认值
如果将环境变量设置为非空字符串,则可以为环境中的所有python进程或从环境继承的环境获得此行为:
例如在Linux或OSX中:
$ export PYTHONUNBUFFERED=TRUE
或Windows:
C:\SET PYTHONUNBUFFERED=TRUE
从文档中:
无缓冲的蟒蛇如果将其设置为非空字符串,则相当于指定-u选项。
补遗
下面是Python 2.7.12中关于打印函数的帮助-注意没有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.
此外,正如这篇博文中所建议的,可以在无缓冲模式下重新打开sys.stdout:
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
每个stdout.write和打印操作之后都会自动刷新。
这是我的版本,它也提供了writeline()和fileno():
class FlushFile(object):
def __init__(self, fd):
self.fd = fd
def write(self, x):
ret = self.fd.write(x)
self.fd.flush()
return ret
def writelines(self, lines):
ret = self.writelines(lines)
self.fd.flush()
return ret
def flush(self):
return self.fd.flush
def close(self):
return self.fd.close()
def fileno(self):
return self.fd.fileno()