Python的解释器默认启用输出缓冲sys.stdout
吗?
如果答案是肯定的,那么禁用它的所有方法是什么?
建议到目前为止:
使用-u
命令行开关
包装sys.stdout
在每次写入后刷新的对象
设置PYTHONUNBUFFERED
env var
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
是否有任何其他方式来设置一些全局标志sys
/ sys.stdout
程序执行过程中?
来自Magnus Lycka的回复邮件列表:
您可以使用"python -u"(或#!/ usr/bin/env python -u等)或通过设置环境变量PYTHONUNBUFFERED来跳过整个python进程的缓冲.
您还可以将sys.stdout替换为其他流,例如在每次调用后执行刷新的包装器.
class Unbuffered(object): def __init__(self, stream): self.stream = stream def write(self, data): self.stream.write(data) self.stream.flush() def writelines(self, datas): self.stream.writelines(datas) self.stream.flush() def __getattr__(self, attr): return getattr(self.stream, attr) import sys sys.stdout = Unbuffered(sys.stdout) print 'Hello'
我宁愿把答案放在如何刷新Python打印输出?或者在Python的print函数中,在调用缓冲区时刷新缓冲区?,但由于它们被标记为这个副本(我不同意),我会在这里回答.
由于Python 3.3 print()支持关键字参数"flush"(参见文档):
print('Hello World!', flush=True)
# 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, and write through # everything. Alternatively, use line_buffering=True to flush on newlines. unbuffered = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), write_through=True) except TypeError: # Python 2 unbuffered = os.fdopen(sys.stdout.fileno(), 'w', 0)
致谢:"塞巴斯蒂安",在Python邮件列表的某个地方.
第三方编辑
最新版本的Python 3不支持
是的.
您可以使用"-u"开关在命令行上禁用它.
或者,您可以在每次写入时在sys.stdout上调用.flush()(或者使用自动执行此操作的对象将其包装)
这与CristóvãoD.Sousa的答案有关,但我还没有发表评论.
使用Python 3的flush
关键字参数以便始终具有无缓冲输出的直接方式是:
import functools print = functools.partial(print, flush=True)
之后,print将始终直接刷新输出(除非flush=False
给出).
注意,(a)这只是部分回答了问题,因为它没有重定向所有输出.不过,我想print
是一个用于创建输出的最常用的方法stdout
/ stderr
Python中,所以这两条线可能覆盖大部分的用例.
注意(b)它只适用于您定义它的模块/脚本.这在编写模块时可能很好,因为它不会弄乱模块sys.stdout
.
Python 2不提供flush
参数,但您可以模拟Python 3类型的print
函数,如/sf/ask/17360801/所述.
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"])
如果不保存旧的sys.stdout,则disable_stdout_buffering()不是幂等的,多次调用将导致如下错误:
Traceback (most recent call last): File "test/buffering.py", line 17, inprint "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.garbage并不是一个好主意,因为它是放置不合理周期的地方,你可能想要检查那些.)
是的,它默认启用.您可以在调用python时在命令行上使用-u选项禁用它.
以下适用于Python 2.6,2.7和3.2:
import os import sys buf_arg = 0 if sys.version_info[0] == 3: os.environ['PYTHONUNBUFFERED'] = '1' buf_arg = 1 sys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg) sys.stderr = os.fdopen(sys.stderr.fileno(), 'a+', buf_arg)
您还可以使用stdbuf实用程序运行Python :
stdbuf -oL python
在Python 3中,您可以使用猴子补丁打印功能,以始终发送flush = True:
_orig_print = print def print(*args, **kwargs): _orig_print(*args, flush=True, **kwargs)
如注释中所指出的,您可以通过以下方式将flush参数绑定到一个值来简化此操作functools.partial
:
print = functools.partial(print, flush=True)