Python程序中的无缓冲标准输出(如python -u)

73

有没有办法在我的代码中获得运行python -u的效果?如果无法做到这一点,那么我的程序是否可以检查是否在-u模式下运行,并在没有时退出并显示错误消息?这是在Linux(Ubuntu 8.10 Server)上的情况。


6
另一种解决方法是设置PYTHONUNBUFFERED环境变量为任何非空字符串。这不在你的代码中 - 必须在Python解释器启动之前设置 - 但比修改启动脚本以添加 "-u" 更容易。 - Beni Cherniavsky-Paskin
2
太好了,谢谢!这对我今天帮助很大。我正在从bash文件(运行uvicorn)启动FastAPI服务,该文件本身是从SystemD .service文件启动的。我意识到我的一些标准输出被缓冲了,只有在程序终止时才会溢出,而不是在我想要看到它的开始时。由于Python启动是几层深的,我试图弄清楚如何说服uvicorn在启动Python时添加“-u”,但是通过这种方法,我能够简单地添加Environment=PYTHONUNBUFFERED=anystringhere到服务定义中!太棒了! - Jeff Saxe
4个回答

52

我能想到的最好方案是:

>>> import os
>>> import sys
>>> unbuffered = os.fdopen(sys.stdout.fileno(), 'w', 0)
>>> unbuffered.write('test')
test>>> 
>>> sys.stdout = unbuffered
>>> print 'test'
test

在GNU/Linux上进行了测试。看起来它在Windows上也应该可以工作。如果我知道如何重新打开sys.stdout,那将会更容易:


在GNU/Linux上测试过,似乎也可以在Windows上工作。如果我知道如何重新打开sys.stdout,这个问题就会容易解决:

sys.stdout = open('???', 'w', 0)

参考文献:
http://docs.python.org/library/stdtypes.html#file-objects
http://docs.python.org/library/functions.html#open
http://docs.python.org/library/os.html#file-object-creation

[编辑]

请注意,在覆盖之前最好关闭sys.stdout。


1
stdout still lives in sys.__stdout__ - Thomas Ahle
23
请注意,这在Py3K中无法正常工作。ValueError: can't have unbuffered text I/O - vbo
2
这个问题的答案已经非常过时了。请参考以下链接中关于Python 3.3+的答案:https://dev59.com/inVD5IYBdhLWcg3wDHDm - xjcl

40

你可以在shebang行中传递-u参数:

#!/usr/bin/python -u

25
看标题:1. OP知道这件事;2.想要通过编程实现。 - Tobu
21
作者暗示使用命令行,没有指示熟悉shell提供的替代调用(shebang)。感谢您的有益反馈。 - mikewaters
15
这似乎不适用于“env技巧”。#!/usr/bin/env python -u。我得到以下错误/usr/bin/env: python -u: No such file or directory。如果我去掉-u,它就能正常工作。 - Aaron McDaid
2
(我又来了!)这是我在上面两个评论中讨论的问题的解决方案:https://dev59.com/pGQm5IYBdhLWcg3wowMF。(但是,是的,这与这里的原始问题无关) - Aaron McDaid
2
正如Aaron所说,简单地在shebang中添加选项是行不通的。相反,将-S选项传递给env命令,像这样:#!/usr/bin/env -S python3 -u - Nico Villanueva
显示剩余2条评论

9
假设您使用的是Windows操作系统:
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

...在Unix系统上:

fl = fcntl.fcntl(sys.stdout.fileno(), fcntl.F_GETFL)
fl |= os.O_SYNC
fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, fl)

(Unix从注释解决方案中复制了过来,而不是链接。)

抱歉,忘记添加了。在Linux(Ubuntu)上。 - Martin DeMello
5
@Martin DeMello:请不要在评论中添加新的事实。请在您的问题中更新新的事实。在评论中添加新的事实很难被发现。 - S.Lott
1
支持Unix、Linux和任何POSIX系统:https://dev59.com/inVD5IYBdhLWcg3wDHDm#1736047 - Tobu
请注意,此方法不适用于Python2(无错误,输出仍被缓冲)。当使用错误的解释器运行脚本时可发现。 - Romuald Brunet

8

编辑 (2020年10月)。如在此回答的注释中指出的那样,在Python3中,stderr也是被缓冲的。

您可以利用stderr从不缓冲的特性,尝试将stdout重定向到stderr:

import sys
#buffered output is here
doStuff()

oldStdout = sys.stdout
sys.stdout = sys.stderr
#unbuffered output from here on

doMoreStuff()
sys.stdout = oldStdout

#the output is buffered again
doEvenMoreStuff()

6
一个hack,但非常可爱 :) 如果您需要单独使用stderr,则不起作用,但是是一个很好的想法。 - Martin DeMello
谢谢。至于分离:你不能得到所有的,对吧 :) - Boris Gorelik
2
"stderr 从不缓冲" - 这已经不再是真的了;在 Python3 中,如果输出到 tty,则 stderr 是行缓冲的,如果输出到文件或管道,则是完全缓冲的。 - Don Hatch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接