关于python:如何刷新print函数的输出?

How to flush output of print function?

如何强制python的print函数输出到屏幕?

这不是禁用输出缓冲的副本-链接问题正在尝试未缓冲的输出,而这是更一般的。这个问题中的顶级答案对这个问题来说太强大或涉及太多(它们不是很好的答案),这个问题可以由一个相对的新手在谷歌上找到。


1
2
import sys
sys.stdout.flush()

默认打印到sys.stdout

参考文献:

  • http://docs.python.org/reference/simple_stmts.html打印语句
  • http://docs.python.org/library/sys.html网站
  • http://docs.python.org/library/stdtypes.html文件对象


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

-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
see man page for details on internal buffering relating to '-u'

这是相关的文件。


由于python 3.3,您可以强制正常的print()函数刷新,而无需使用sys.stdout.flush();只需将"flush"关键字参数设置为true。从文档中:

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

Print objects to the stream file, separated by sep and followed by end. sep, end and file, if present, must be given as keyword arguments.

All non-keyword arguments are converted to strings like str() does and written to the stream, separated by sep and followed by end. Both sep and end must be strings; they can also be None, which means to use the default values. If no objects are given, print() will just write end.

The file argument must be an object with a write(string) method; if it is not present or None, sys.stdout will be used. Whether output is buffered is usually determined by file, but if the flush keyword argument is true, the stream is forcibly flushed.


How to flush output of 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进程(并取消设置变量以撤消此操作)。

Python 3.3 +

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

1
print('foo', flush=True)

python 2(或<3.3)

它们没有将flush参数反向移植到python 2.7,因此如果您使用的是python 2(或小于3.3),并且想要与2和3兼容的代码,我建议您使用以下兼容代码。(注意,EDOCX1[9]导入必须位于/非常"靠近模块顶部"):

1
2
3
4
5
6
7
8
9
10
11
12
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语句:

1
2
3
import sys
print 'delayed output'
sys.stdout.flush()

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

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

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

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

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

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

1
2
>>> print('foo')
foo

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

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

请再次注意,这只会更改当前全局范围,因为当前全局范围上的打印名称将覆盖内置的print函数(如果在当前全局范围中使用python 2,则取消对兼容性函数的引用)。

如果要在函数内部而不是模块的全局范围内执行此操作,则应为其指定一个不同的名称,例如:

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

如果您在函数中声明它是全局的,那么您将在模块的全局命名空间中对其进行更改,因此您只需将其放在全局命名空间中,除非具体的行为正是您想要的。

更改进程的默认值

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

1
$ python -u script.py

1
$ python -um package.module

来自文档:

Force stdin, stdout and stderr to be totally unbuffered. On systems where it matters, also put stdin, stdout and stderr in binary mode.

Note that there is internal buffering in file.readlines() and File Objects (for line in sys.stdin) which is not influenced by this option. To work around this, you will want to use file.readline() inside a while 1: loop.

更改shell操作环境的默认值

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

例如,在Linux或OSX中:

1
$ export PYTHONUNBUFFERED=TRUE

或窗口:

1
C:\SET PYTHONUNBUFFERED=TRUE

来自文档:

PYTHONUNBUFFERED

If this is set to a non-empty string it is equivalent to specifying the -u option.

补遗

下面是关于python 2.7.12中print函数的帮助-请注意,没有flush参数:

1
2
3
4
5
6
7
8
9
10
11
>>> from __future__ import print_function
>>> help(print)
print(...)
    print(value, ..., sep=' ', end='
'
, 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

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

之后,每个stdout.writeprint操作将自动冲洗。


使用python 3.x扩展了print()函数:

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

所以,你可以这样做:

1
print("Visiting toilet", flush=True)

python文档条目


使用-u命令行开关是可行的,但有点笨拙。这意味着如果用户在没有-u选项的情况下调用脚本,程序可能会出现错误的行为。我通常使用自定义的stdout,如下所示:

1
2
3
4
5
6
7
8
9
10
class flushfile(object):
  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)都将自动被flushed。


为什么不尝试使用未缓冲的文件?

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

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


1
2
3
import sys
print 'This will be output immediately.'
sys.stdout.flush()

丹的想法不太管用:

1
2
3
4
5
6
7
8
9
10
11
12
#!/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"

结果:

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

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

stdout and stderr needn’t be built-in
file objects: any object is acceptable
as long as it has a write() method
that takes a string argument.

所以改变

1
class flushfile(file):

1
class flushfile(object):

让它工作得很好。


这是我的版本,它也提供了writelines()和fileno():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()


喜欢丹的解决方案!对于Python 3做:

1
2
3
4
5
6
7
8
import io,sys
class flushfile:
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()
sys.stdout = flushfile(sys.stdout)


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

1
2
3
def print(*objects, sep=' ', end='
'
, file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)


我在Python3.4中是这样做的:

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