如何刷新打印功能的输出?

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

1041077 次浏览

在Python 3中,#0可以接受可选的flush参数:

print("Hello, World!", flush=True)

在Python 2中,调用print后,执行:

import syssys.stdout.flush()

默认情况下,#0打印到#1(有关文件对象的更多信息,请参阅留档)。

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

-u:无缓冲的二进制stdout和stderr;还有PYTHONUNBUFFERED=x有关'-u'内部缓冲的详细信息,请参阅手册页

这里是相关留档

使用-u命令行开关可以工作,但它有点笨拙。这意味着如果用户在没有-u选项的情况下调用脚本,程序可能会表现不正确。我通常使用自定义stdout,如下所示:

class flushfile:def __init__(self, f):self.f = f
def write(self, x):self.f.write(x)self.f.flush()
import syssys.stdout = flushfile(sys.stdout)

…现在所有print调用(隐式使用sys.stdout)将自动flush ed。

Dan的主意不起作用:

#!/usr/bin/env pythonclass flushfile(file):def __init__(self, f):self.f = fdef write(self, x):self.f.write(x)self.f.flush()
import syssys.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不需要内置文件对象:任何对象都可以接受只要它有一个写()方法这需要一个字符串参数。

如此变化

class flushfile(file):

class flushfile(object):

使它工作得很好。

使用未缓冲的文件:

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

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

这是我的版本,它也提供了写入线()和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()

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

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

每个stdout.writeprint操作将在之后自动刷新。

从Python 3.3开始,您可以强制普通的print()函数刷新,而无需使用sys.stdout.flush();只需将“flush”关键字参数设置为true。从留档

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

将对象打印到流文件,用sep分隔,后跟end。sep、end和file(如果存在)必须作为关键字参数给出。

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

文件参数必须是一个带有写(字符串)方法的对象;如果它不存在或无,将使用sys.stdout。输出是否被缓冲通常由文件决定,但如果flush关键字参数为true,则会强制刷新流。

我在Python 3.4中这样做:

'''To write to screen in real-time'''message = lambda x: print(x, flush=True, end="")message('I am flushing out now...')

在Python 3. x中,print()函数得到了扩展:

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

所以,你可以只做:

print("Visiting toilet", flush=True)

Python文档条目

如何刷新Python print的输出?

我建议五种方法来做到这一点:

  • 在Python 3中,调用print(..., flush=True)(flush参数在Python 2的print函数中不可用,并且没有print语句的模拟)。
  • 在输出文件上调用file.flush()(我们可以包装python 2的print函数来执行此操作),例如sys.stdout
  • 将此应用于模块中带有部分函数的每个打印函数调用,
    print = partial(print, flush=True)应用于模块全局。
  • 将此应用于传递给解释器命令的标志(-u)的进程
  • 使用PYTHONUNBUFFERED=TRUE将其应用于环境中的每个python进程(并取消设置变量以撤消此操作)。

python3.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_functionimport sys
if sys.version_info[:2] < (3, 3):old_print = printdef 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()

上面的兼容性代码将涵盖大多数用途,但为了更彻底的处理,查看#0模块

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

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

将一个模块中的默认值更改为flush=True

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

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

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

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

我们可以看到它像正常一样工作:

>>> print('foo')foo

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

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

请再次注意,这只会更改当前全局作用域,因为当前全局作用域上的print名称将遮盖内置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中的行)中存在不受此选项影响的内部缓冲。要解决此问题,您需要在而1:循环中使用file.readline()。

更改shell操作环境的默认值

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

例如,在Linux或OSX中:

$ export PYTHONUNBUFFERED=TRUE

或windows:

C:\SET PYTHONUNBUFFERED=TRUE

文档

肾上腺素

如果将其设置为非空字符串,则等效于指定-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.

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

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

我首先很难理解刷新选项是如何工作的。我想做一个“加载显示”,这是我找到的解决方案:

for i in range(100000):print('{:s}\r'.format(''), end='', flush=True)print('Loading index: {:d}/100000'.format(i+1), end='')

第一行刷新前一个打印,第二行打印一个新的更新消息。我不知道这里是否存在单行语法。