默认情况下,Python的解释器是否为sys.stdout
?
如果答案是肯定的,那么禁用它的所有方法是什么?
目前的建议:
-u
命令行开关sys.stdout
PYTHONUNBUFFERED
env var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
有没有其他方法可以在执行期间以编程方式在sys
/ sys.stdout
中设置一些全局标志?
答案 0 :(得分:379)
来自Magnus Lycka answer on a mailing list:
你可以跳过整个缓冲 使用“python -u”的python进程 (或#!/ usr / bin / env python -u等)或者 设置环境变量 PYTHONUNBUFFERED。
你也可以用。替换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'
答案 1 :(得分:84)
我宁愿将答案放在How to flush output of Python print?或Python's print function that flushes the buffer when it's called?中,但由于它们被标记为此答案的副本(我不同意),我将在此处回答。
由于Python 3.3 print()支持关键字参数“flush”(see documentation):
print('Hello World!', flush=True)
答案 2 :(得分:72)
# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
致谢:“塞巴斯蒂安”,在Python邮件列表的某个地方。
第三方编辑
最近版本的Python 3不支持
答案 3 :(得分:46)
是的,是的。
您可以使用“-u”开关在命令行上禁用它。
或者,您可以在每次写入时在sys.stdout上调用.flush()(或者使用自动执行此操作的对象将其包装)
答案 4 :(得分:13)
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, 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.garbage并不是一个好主意,因为它是放置不合理周期的地方,你可能想检查那些。)
答案 5 :(得分:12)
以下适用于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)
答案 6 :(得分:12)
这与CristóvãoD。Sousa的答案有关,但我还没有发表评论。
使用 Python 3 的flush
关键字参数以便始终具有无缓冲输出的直接方式是:
import functools
print = functools.partial(print, flush=True)
之后,print将始终直接刷新输出(除了flush=False
之外)。
注意,(a)这只是部分回答了问题,因为它没有重定向所有输出。但我想print
是在python中创建stdout
/ stderr
输出的最常用方法,因此这两行可能涵盖了大部分用例。
注意(b)它只适用于您定义它的模块/脚本。编写模块时这可能很好,因为它不会弄乱sys.stdout
。
Python 2 不提供flush
参数,但您可以模拟Python 3类print
函数,如此处所述https://stackoverflow.com/a/27991478/3734258。
答案 7 :(得分:10)
是的,默认情况下已启用。您可以在调用python时在命令行上使用-u选项禁用它。
答案 8 :(得分:7)
您还可以使用stdbuf实用程序
运行Python stdbuf -oL python <script>
答案 9 :(得分:3)
您还可以使用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)
答案 10 :(得分:3)
Variant工作没有崩溃(至少在win32; python 2.7,ipython 0.12),然后随后调用(多次):
def DisOutBuffering():
if sys.stdout.name == '<stdout>':
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
if sys.stderr.name == '<stderr>':
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
答案 11 :(得分:3)
(我发表评论,但它以某种方式迷失了。所以,再次:)
正如我所注意到的,CPython(至少在Linux上)的行为取决于输出的位置。如果它转到tty,则在每个'\n'
后刷新输出
如果它进入管道/过程,则它被缓冲,您可以使用基于flush()
的解决方案或上面推荐的 -u 选项。
与输出缓冲有关:
如果使用
for line in sys.stdin:
...
然后 CPython 中的 for 实现将收集输入一段时间,然后为一堆输入行执行循环体。如果您的脚本即将为每个输入行写入输出,这可能看起来像输出缓冲,但它实际上是批处理,因此,flush()
等技术都不会有帮助。
有趣的是,您在 pypy 中没有此行为。
为避免这种情况,您可以使用
while True:
line=sys.stdin.readline()
...
答案 12 :(得分:3)
可以使用调用write
的方法覆盖sys.stdout
的仅 flush
方法。建议的方法实现如下。
def write_flush(args, w=stdout.write):
w(args)
stdout.flush()
w
参数的默认值将保留原始write
方法参考。 write_flush
定义后,原始的write
可能会被覆盖。
stdout.write = write_flush
该代码假定stdout
以from sys import stdout
方式导入{。}}。
答案 13 :(得分:2)
您可以创建一个无缓冲的文件并将此文件分配给sys.stdout。
import sys
myFile= open( "a.log", "w", 0 )
sys.stdout= myFile
你不能神奇地改变系统提供的标准输出;因为它是由操作系统提供给你的python程序的。
答案 14 :(得分:1)
获得无缓冲输出的一种方法是使用sys.stderr
而不是sys.stdout
或简单地调用sys.stdout.flush()
来明确强制进行写入。
您可以通过执行以下操作轻松重定向打印的所有内容:
import sys; sys.stdout = sys.stderr
print "Hello World!"
或仅针对特定print
语句重定向:
print >>sys.stderr, "Hello World!"
要重置标准输出,您可以这样做:
sys.stdout = sys.__stdout__
答案 15 :(得分:1)
在Python 3中,您可以使用猴子补丁打印功能,以始终发送flush = True:
_orig_print = print
def print(*args, **kwargs):
_orig_print(*args, flush=True, **kwargs)