在Python的sys.stdout解释器中默认启用输出缓冲吗?

如果答案是肯定的,那么有哪些方法可以禁用它?

目前的建议:

使用-u命令行开关 包装系统。每次写入后刷新的对象中的标准输出 设置PYTHONUNBUFFERED env变量 sys。Stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

是否有其他方法在sys/sys中设置全局标志。在执行期间以编程方式Stdout ?


如果只是想在使用打印的特定写入之后刷新,请参阅如何刷新打印函数的输出?。


当前回答

# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
import io, os, sys
try:
    # Python 3, open as binary, then wrap in a TextIOWrapper with write-through.
    sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), write_through=True)
    # If flushing on newlines is sufficient, as of 3.7 you can instead just call:
    # sys.stdout.reconfigure(line_buffering=True)
except TypeError:
    # Python 2
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

工作人员:“塞巴斯蒂安”,在Python邮件列表的某个地方。

其他回答

我宁愿把我的答案放在如何刷新打印功能的输出?或者在Python的print函数中,当它被调用时,会刷新缓冲区?,但由于它们被标记为这一个的副本(我不同意),我将在这里回答它。

从Python 3.3开始,print()支持关键字参数"flush"(参见文档):

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

这与Cristóvão D. Sousa的回答有关,但我还不能评论。

使用Python 3的flush关键字参数以始终拥有未缓冲输出的直接方法是:

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

然后,print将始终直接刷新输出(除非flush=False给出)。

注意,(a)这只回答了部分问题,因为它没有重定向所有输出。但我猜打印是在python中创建输出到stdout/stderr的最常用方法,所以这两行可能涵盖了大多数用例。

注意(b)它只在定义它的模块/脚本中工作。这在编写模块时很好,因为它不会混淆sys.stdout。

Python 2不提供flush参数,但您可以模拟Python 3类型的打印函数,如此处所述https://stackoverflow.com/a/27991478/3734258。

您还可以使用fcntl动态更改文件标志。

fl = fcntl.fcntl(fd.fileno(), fcntl.F_GETFL)
fl |= os.O_SYNC # or os.O_DSYNC (if you don't care the file timestamp updates)
fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, fl)

重写sys的只写方法是可能的。带有一个调用flush的Stdout。建议的方法实现如下所示。

def write_flush(args, w=stdout.write):
    w(args)
    stdout.flush()

w参数的默认值将保留原来的写入方法引用。定义了write_flush之后,可能会覆盖原来的写操作。

stdout.write = write_flush

代码假设stdout是从sys import stdout以这种方式导入的。

def disable_stdout_buffering():
    # Appending to gc.garbage is a way to stop an object from being
    # destroyed.  If the old sys.stdout is ever collected, it will
    # close() stdout, which is not good.
    gc.garbage.append(sys.stdout)
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

# Then this will give output in the correct order:
disable_stdout_buffering()
print "hello"
subprocess.call(["echo", "bye"])

不拯救旧的系统。Stdout, disable_stdout_buffering()不是幂等的,多次调用将导致这样的错误:

Traceback (most recent call last):
  File "test/buffering.py", line 17, in <module>
    print "hello"
IOError: [Errno 9] Bad file descriptor
close failed: [Errno 9] Bad file descriptor

另一种可能性是:

def disable_stdout_buffering():
    fileno = sys.stdout.fileno()
    temp_fd = os.dup(fileno)
    sys.stdout.close()
    os.dup2(temp_fd, fileno)
    os.close(temp_fd)
    sys.stdout = os.fdopen(fileno, "w", 0)

(附加到gc。垃圾并不是一个好主意,因为它是放置不可释放循环的地方,您可能需要检查它们。)