1458

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

4

13 回答 13

1716

在 Python 3 中,print可以采用可选flush参数:

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

在 Python 2 中你必须做

import sys
sys.stdout.flush()

打电话后print。默认情况下,print打印到sys.stdout(有关文件对象的更多信息,请参阅文档)。

于 2008-10-23T18:04:59.083 回答
396

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

-u :无缓冲的二进制标准输出和标准错误;也 PYTHONUNBUFFERED=x 有关与“-u”相关的内部缓冲的详细信息,请参见手册页

这是相关文档

于 2008-10-23T18:06:49.377 回答
336

从 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() 将只写 end。

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

于 2014-04-17T20:10:31.917 回答
244

如何刷新 Python 打印的输出?

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

  • 在 Python 3 中,调用print(..., flush=True)(flush 参数在 Python 2 的 print 函数中不可用,并且 print 语句没有类似物)。
  • 调用file.flush()输出文件(我们可以包装 python 2 的 print 函数来执行此操作),例如,sys.stdout
  • 将此应用于模块中具有部分函数的每个打印函数调用,
    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 来更改打印功能的默认值:

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

文档

强制标准输入、标准输出和标准错误完全无缓冲。在重要的系统上,还将标准输入、标准输出和标准错误置于二进制模式。

请注意,file.readlines() 和文件对象(用于 sys.stdin 中的行)中有内部缓冲,不受此选项的影响。要解决这个问题,您需要在 while 1: 循环中使用 file.readline()。

更改 shell 操作环境的默认值

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

例如,在 Linux 或 OSX 中:

$ export PYTHONUNBUFFERED=TRUE

或窗口:

C:\SET PYTHONUNBUFFERED=TRUE

来自文档

Python无缓冲

如果将其设置为非空字符串,则等效于指定 -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.
于 2016-02-17T21:01:03.190 回答
70

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

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

之后会自动刷新每个stdout.writeand操作。print

于 2012-02-27T08:38:27.307 回答
67

在 Python 3.x 中,该print()功能得到了扩展:

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

所以,你可以这样做:

print("Visiting toilet", flush=True)

Python 文档条目

于 2015-10-21T17:23:32.100 回答
39

使用-u命令行开关有效,但有点笨拙。这意味着如果用户在没有-u选项的情况下调用脚本,程序可能会出现错误的行为。我通常使用 custom 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编辑。

于 2008-10-23T19:54:26.740 回答
19

使用无缓冲文件:

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

或者

sys.stdout = open('out.log', 'a', 0)
于 2009-04-12T10:57:58.520 回答
15

在 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)
于 2016-05-15T19:13:34.027 回答
14

丹的想法并不完全奏效:

#!/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):

让它工作得很好。

于 2008-11-13T22:15:25.260 回答
12

这是我的版本,它也提供了 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()
于 2011-05-19T08:20:36.630 回答
7

我在 Python 3.4 中这样做了:

'''To write to screen in real-time'''
message = lambda x: print(x, flush=True, end="")
message('I am flushing out now...')
于 2015-06-06T11:10:54.547 回答
4

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

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

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

于 2019-11-07T02:49:50.060 回答