Pythonのsys.stdout
のインタプリタでは、出力バッファリングはデフォルトで有効になっていますか?
答えが肯定的であれば、それを無効にするためのすべての方法は何ですか?
これまでの提案:
-u
コマンドラインスイッチを使うsys.stdout
をラップします。PYTHONUNBUFFERED
env varを設定しますsys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
実行中にプログラムでsys
/sys.stdout
にグローバルフラグを設定する他の方法はありますか?
"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 printの出力をフラッシュするにはどうすればいいですか? または 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)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
クレジット: "Sebastian"、Pythonメーリングリストのどこかにあります。
第三者による編集
最近のバージョンのPython 3ではサポートされていません
はい、そうです。
コマンドラインで "-u"スイッチを使って無効にすることができます。
あるいは、書き込みのたびにsys.stdoutで.flush()を呼び出すこともできます(またはこれを自動的に行うオブジェクトでラップすることもできます)。
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に追加するのは、それほど不自然なサイクルが発生するところであり、それらをチェックしたいと思うかもしれないので、それほど良い考えではありません。)
これはCristóvãoD. Sousaの答えに関連していますが、私はまだコメントできませんでした。
常にバッファリングされていない出力を得るためにPython 3のflush
キーワード引数を使用する簡単な方法は次のとおりです。
import functools
print = functools.partial(print, flush=True)
その後、printは常に出力を直接フラッシュします(flush=False
が指定されている場合を除く)。
(a)これはすべての出力をリダイレクトするわけではないので、これは部分的にしか質問に答えないことに注意してください。しかし、私はprint
がpythonでstdout
/stderr
への出力を作成するための最も一般的な方法であると思うので、これらの2行はおそらくほとんどのユースケースをカバーします。
それがあなたがそれを定義したモジュール/スクリプトでだけ働くことに注意してください(b)。 sys.stdout
をめちゃくちゃにしないので、モジュールを書くときこれは良いことです。
Python 2はflush
引数を提供していませんが、ここで説明されているようにPython 3タイプのprint
関数をエミュレートすることができます https://stackoverflow.com/a/27991478/3734258 。
以下は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)
はい、デフォルトで有効になっています。 pythonを呼び出すときにコマンドラインで-uオプションを使用すると無効にできます。
Pythonを stdbuf ユーティリティで実行することもできます。
stdbuf -oL python <script>
(私はコメントを投稿しましたが、それはどういうわけか紛失しました。それで、また:)
私が気づいたように、(少なくともLinux上で)CPythonは出力がどこに行くかによって異なった振る舞いをします。それがttyになると、出力はそれぞれの\n'
の後にフラッシュされます
もしそれがパイプ/プロセスに行くなら、それはバッファされていて、あなたはflush()
ベースの解決法か上で推薦された - uオプションを使うことができます。
出力バッファリングと多少関係があります。
入力の行を次のように繰り返すと
for line in sys.stdin:
...
次に、CPythonのfor実装は、しばらくの間入力を収集してから、一連の入力行に対してループ本体を実行します。スクリプトが各入力行に出力を書き込もうとしている場合、これは出力バッファリングのように見えるかもしれませんが、実際にはバッチ処理です。したがって、flush()
などの手法は役に立ちません。興味深いことに、pypyではこのような振る舞いはありません。これを避けるためには、
while True: line=sys.stdin.readline()
...
sys.stdout
のwrite
メソッドのみを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
のようにインポートされていることを前提としています。
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)
クラッシュすることなく(少なくとも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)
バッファなしファイルを作成し、このファイルをsys.stdoutに割り当てることができます。
import sys
myFile= open( "a.log", "w", 0 )
sys.stdout= myFile
システム提供の標準出力を魔法のように変更することはできません。それはOSによってあなたのPythonプログラムに供給されるからです。
Python 3では、print関数をmonkey-patchして、常にflush = Trueを送ることができます。
_orig_print = print
def print(*args, **kwargs):
_orig_print(*args, flush=True, **kwargs)
バッファリングされていない出力を取得する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__