【问题标题】:How can I flush the output of the print function (unbuffer python output)?如何刷新打印函数的输出(取消缓冲 python 输出)?
【发布时间】:2010-09-18 20:20:38
【问题描述】:

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

【问题讨论】:

  • python -u <script.py> 为我工作(强制刷新,无缓冲),无需修改脚本。
  • 请注意,该行为在 IDE 中被破坏了。例如,PyCharm 在调试控制台中正常工作,但在运行控制台中不能正常工作。您可能需要确定问题存在于常规终端中。

标签: python python-3.x printing flush


【解决方案1】:

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

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

在 Python 2 中你必须这样做

import sys
sys.stdout.flush()

在致电print 之后。默认情况下,print 打印到sys.stdout(有关file objects 的更多信息,请参阅文档)。

【讨论】:

  • 如果我这样做sys.stdout.flush() 可以避免使用flush 关键字吗?我的文件中有很多打印件并且不想更改它们+我希望我的文件始终刷新并且我不想写它。总是冲洗是我想要的。将sys.stdout.flush() 放在顶部就足够了吗? (我使用的是 python 3 及以上版本)
  • 不,每次调用 print 时都需要执行 sys.stdout.flush()(或在 Python 3 中使用 print(..., flush=True))。检查this answer 以获取可能对您有用的另一种解决方案。
  • sys.stdout.flush() 也适用于 Python 3。
  • python -u <script.py> 为我工作,无需修改脚本。
  • 可能很晚,但如果您希望您的打印件始终像@Charlie Parker 一样冲洗,您可以使用print = functools.partial(print, flush=True)
【解决方案2】:

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

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

这里是relevant documentation

【讨论】:

  • 如果您在 Linux/Unix 平台上运行它,您可以在解释器命令行(脚本文件的第一行)中添加 -u,因此将第一行从(类似于) #!/usr/bin/python3#!/usr/bin/python3 -u - 现在当您运行脚本时(例如 ./my_script.py),-u 将始终为您添加
【解决方案3】:

使用-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)将自动变为flushed。

【讨论】:

  • 我建议不要从文件继承然后通过添加委派给标准输出。 def __getattr__(self,name): return object.__getattribute__(self.f, name)
  • 如果没有@diedthreetimes 的评论建议的更改,我得到“ValueError: I/O operation on closed file”
【解决方案4】:

Dan's idea 不太好用:

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

让它工作得很好。

【讨论】:

  • 不投票,因为这是@Dan 的解决方案...(您应该评论 Dan 的帖子而不是复制他的解决方案)
【解决方案5】:

使用无缓冲文件:

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

或者

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

【讨论】:

  • 他不想创建无缓冲文件;他想让现有的标准输出(重定向到控制台、终端或其他任何东西:不能更改)无缓冲。
【解决方案6】:

这是我的版本,它也提供了 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 类。
【解决方案7】:

另外,正如this blog post 中所建议的,可以在无缓冲模式下重新打开sys.stdout

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

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

【讨论】:

  • 在 python 2.7 的 Ubuntu 12.04 上,这给了我UnsupportedOperation: IOStream has no fileno.
  • 哎呀,Python 3 发现了。它不会让我执行这段代码!
  • 我被这个成语弄糊涂了。在你这样做之后,现在是不是有两个类似文件的对象(原始的 sys.stdout 和新的 sys.stdout)都认为他们“拥有”文件号?这很糟糕,对吧?
  • 如果您查看 de docs,buffering=0 仅适用于二进制模式。 buffering is an optional integer used to set the buffering policy. Pass 0 to switch buffering off (only allowed in binary mode), 1 to select line buffering (only usable in text mode), and an integer &gt; 1 to indicate the size in bytes of a fixed-size chunk buffer.
【解决方案8】:

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

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

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

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

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

【讨论】:

  • 如果我这样做sys.stdout.flush() 可以避免使用flush 关键字吗?我的文件中有很多打印件并且不想更改它们+我希望我的文件始终刷新并且我不想写它。总是冲洗是我想要的。将sys.stdout.flush() 放在顶部就足够了吗? (我使用的是 python 3 及以上版本)
  • 顺便说一句,import sys sys.stdout.flush() 仍然适用于 python3 吗?我宁愿不必修改我的整个脚本来强制刷新。
【解决方案9】:

我在 Python 3.4 中是这样做的:

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

【讨论】:

【解决方案10】:

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

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

所以,你可以这样做:

print("Visiting toilet", flush=True)

Python Docs Entry

【讨论】:

【解决方案11】:

如何刷新 Python print 的输出?

我提出了五种方法:

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

Python 3.3+

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

print('foo', flush=True) 

Python 2(或

他们没有将 flush 参数反向移植到 Python 2.7 因此,如果您使用的是 Python 2(或低于 3.3),并且想要与 2 和 3 兼容的代码,我建议您使用以下兼容性代码。 (注意__future__ 导入必须位于/非常“靠近top of your module”):

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

上述兼容性代码将涵盖大多数用途,但要进行更彻底的处理,see the six module

或者,您可以在打印后调用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

来自docs

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

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

更改 shell 运行环境的默认值

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

例如,在 Linux 或 OSX 中:

$ export PYTHONUNBUFFERED=TRUE

或 Windows:

C:\SET PYTHONUNBUFFERED=TRUE

来自docs

PYTHONUNBUFFERED

如果设置为非空字符串,则相当于指定 -u 选项。


附录

这是 Python 2.7.12 中有关打印功能的帮助 - 请注意,没有 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() 通过未来导入)”bugs.python.org/issue28458
  • 这应该是公认的答案。提供解决方法和大量信息。
  • 如果我这样做sys.stdout.flush() 可以避免使用flush 关键字吗?我的文件中有很多打印件并且不想更改它们+我希望我的文件始终刷新并且我不想写它。总是冲洗是我想要的。将sys.stdout.flush() 放在顶部就足够了吗? (我使用的是python 3及以上版本)
  • 不,但是您可以在模块顶部执行类似import functools; print = functools.partial(print, flush=True) 的操作(例如在导入之后),甚至可以在builtins.print 将其分配给名称print 以实现整个流程的适用性.
  • 喜欢import functools; print2 = functools.partial(print, flush=True); builtins.print=print2? @AaronHall
【解决方案12】:

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

【讨论】:

  • 考虑到所有其他高质量的响应,这个答案似乎有点轻。您可能需要添加更多内容。
【解决方案13】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-19
    • 2022-12-29
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    相关资源
    最近更新 更多