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


1215

如何强制将Python的打印功能输出到屏幕?

这与“ 禁用输出缓冲”不是重复的-链接的问题正在尝试无缓冲输出,尽管这更普遍。对于这个问题,最重要的答案太过强大或牵扯太多(对于这个问题,它们不是很好的答案),这个问题可以由相对新手在Google上找到。

Answers:


1425

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

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

在Python 2上,您必须做

import sys
sys.stdout.flush()

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


346

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

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

这是相关的文档


320

从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,则将强制刷新流。


197

如何刷新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

文档

强制stdin,stdout和stderr完全没有缓冲。在重要的系统上,还将stdin,stdout和stderr置于二进制模式。

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

更改Shell操作环境的默认值

如果将环境变量设置为非空字符串,则可以在环境或从该环境继承的环境中的所有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.

对于从较低版本的Python进行的好奇迁移:该__future__版本未包含该版本,flush因为“在Python 3.3中添加了flush参数(在print()通过将来的导入反向
Oliver

69

另外,如本博客中所建议,可以sys.stdout在无缓冲模式下重新打开:

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

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


2
在python 2.7中的Ubuntu 12.04上,这给了我UnsupportedOperation: IOStream has no fileno.
drevicko

3
糟糕,Python 3发现了。它不会让我执行这段代码!
EKons,2016年

这个成语让我感到困惑。完成此操作之后,现在是否不存在两个都认为它们“拥有”文件名的类文件对象(原始sys.stdout和新sys.stdout)?不好,对吧?
唐·哈奇


36

使用-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编辑。


4
我建议不要从文件继承,然后通过添加委托给stdout。def __getattr__(self,name): return object.__getattribute__(self.f, name)
13年

2
没有@diedthreetimes的注释所建议的更改,我会收到“ ValueError:对已关闭文件的I / O操作”
blueFast 2015年

19

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

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

要么

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

1
他不想创建一个无缓冲的文件。他想使现有的标准输出(重定向到控制台,终端或其他设备:不得更改)不加缓冲。
blueFast 2015年

13

丹的想法不太有效:

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

使它工作正常。


17
没有投票,因为这是
@Dan

8

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

优越的解决方案。而且有效。在Python 3.4.0上测试。使用从派生的其他版本,file我得到一个错误。没有file课。
Colin D Bennett

6

在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)

2
考虑到所有其他高质量的回答,这个答案似乎有点不足。您可能需要添加更多内容。
分号和导管胶带

5

我在Python 3.4中这样做:

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

2

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.