如何强制将 Python 的打印功能输出到屏幕?
这不是 “ 禁用输出缓冲”的重复项 - 链接的问题正在尝试无缓冲输出,尽管这更普遍。对于这个问题,最重要的答案太过强大或牵扯太多(对于这个问题,它们不是很好的答案),这个问题可以由相对新手在 Google 上找到。
在 Python 3 上, print
可以使用可选的flush
参数
print("Hello world!", flush=True)
在 Python 2 上,您必须做
import sys
sys.stdout.flush()
在调用print
。默认情况下, print
打印到sys.stdout
(有关文件对象的更多信息,请参阅文档)。
运行python -h
,我看到一个命令行选项 :
-u:无缓冲的二进制 stdout 和 stderr; 也 PYTHONUNBUFFERED = x 有关与 '-u' 有关的内部缓冲的详细信息,请参见手册页
这是相关的文档 。
从 Python 3.3 开始,您可以强制正常的print()
函数刷新,而无需使用sys.stdout.flush()
; 只需将 “flush” 关键字参数设置为 true。从文档中 :
print(* objects,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 打印输出?
我建议这样做的五种方法:
print(..., flush=True)
(flush 参数在 Python 2 的 print 函数中不可用,并且 print 语句没有类似物)。 file.flush()
(我们可以包装 python 2 的 print 函数来执行此操作),例如sys.stdout
print = partial(print, flush=True)
应用于模块全局。 -u
)将其应用于进程PYTHONUNBUFFERED=TRUE
将其应用于环境中的每个 python 进程(并取消设置变量以撤消此操作)。 使用 Python 3.3 或更高版本,您可以只提供flush=True
作为print
函数的关键字参数:
print('foo', flush=True)
他们没有将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 来更改打印功能的默认值:
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()和文件对象(sys.stdin 中的行)具有内部缓冲,不受此选项的影响。要解决此问题,您将需要在 while 1:循环内使用 file.readline()。
如果将环境变量设置为非空字符串,则可以针对该环境或从该环境继承的环境中的所有 python 进程获得此行为:
例如,在 Linux 或 OSX 中:
$ export PYTHONUNBUFFERED=TRUE
或 Windows:
C:\SET PYTHONUNBUFFERED=TRUE
从文档 :
PYTHONUNBUFFERD
如果将其设置为非空字符串,则等效于指定 - 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.
也如本博客中所建议的那样,可以在非缓冲模式下重新打开sys.stdout
:
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
每个stdout.write
和print
操作将在之后自动刷新。
使用 Python 3.x, print()
函数得到了扩展:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
因此,您可以执行以下操作:
print("Visiting toilet", flush=True)
使用-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)
... 现在,您的所有print
调用(隐式使用sys.stdout
)将被自动flush
。
为什么不尝试使用未缓冲的文件?
f = open('xyz.log', 'a', 0)
要么
sys.stdout = open('out.log', 'a', 0)
丹的想法不太奏效:
#!/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):
至
class flushfile(object):
使它工作正常。
这是我的版本,它也提供 writelines()和 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()