609

Pythonのインタプリタでは、出力バッファリングがデフォルトで有効になっていますsys.stdoutか?

答えが肯定的である場合、それを無効にするすべての方法は何ですか?

これまでの提案:

  1. -uコマンドラインスイッチを使用する
  2. sys.stdout書き込みのたびにフラッシュするオブジェクトでラップします
  3. PYTHONUNBUFFEREDenvvarを設定します
  4. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

sys実行中に/sys.stdoutプログラムでグローバルフラグを設定する他の方法はありますか?

4

16 に答える 16

487

メーリングリストのMagnusLyckaの回答から:

「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'
于 2008-09-20T09:24:31.307 に答える
179

印刷機能の出力をフラッシュする方法に答えを入れたいですか?または、呼び出されたときにバッファをフラッシュするPythonのprint関数で?、しかし、これらはこれの複製としてマークされているので(私は同意しません)、ここで答えます。

Python 3.3以降、print()はキーワード引数「flush」をサポートしています(ドキュメントを参照)。

print('Hello World!', flush=True)
于 2013-02-06T13:05:23.863 に答える
86
# 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)

クレジット: "Sebastian"、Python メーリング リストのどこかにあります。

于 2008-10-08T07:23:10.007 に答える
67

はい、そうです。

コマンドラインで「-u」スイッチを使用して無効にすることができます。

または、書き込みのたびにsys.stdoutで.flush()を呼び出すこともできます(または、これを自動的に実行するオブジェクトでラップします)。

于 2008-09-20T09:25:36.763 に答える
33

これは Cristóvão D. Sousa の回答に関連していますが、まだコメントできませんでした。

常にバッファリングされていない出力を得るために、 Python 3flushのキーワード引数を使用する簡単な方法は次のとおりです。

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

その後、print は常に出力を直接フラッシュします (flush=False与えられた場合を除く)。

(a)すべての出力をリダイレクトするわけではないため、これは部分的にしか質問に答えないことに注意してください。しかし、Python で/printへの出力を作成する最も一般的な方法は、おそらくこれらの 2 行でほとんどのユース ケースをカバーしていると思います。stdoutstderr

(b) 定義したモジュール/スクリプトでのみ機能することに注意してください。これは、sys.stdout.

Python 2は引数を提供しませんが、https://stackoverflow.com/a/27991478/3734258flushで説明されているように、Python 3 タイプのprint関数をエミュレートできます。

于 2016-10-20T18:30:43.340 に答える
15
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に追加することは、解放できないサイクルが発生する場所であるため、あまり良い考えではありません。それらを確認することをお勧めします。)

于 2010-09-09T15:37:53.240 に答える
13

以下は、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)
于 2014-04-12T18:43:28.173 に答える
12

はい、デフォルトで有効になっています。Pythonを呼び出すときに、コマンドラインで-uオプションを使用して無効にすることができます。

于 2008-09-20T09:26:19.353 に答える
5

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)
于 2009-11-15T00:01:01.810 に答える
4

のメソッドのみ を、 を呼び出すwriteメソッドでオーバーライドすることができます。推奨されるメソッドの実装を以下に示します。sys.stdoutflush

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

w引数のデフォルト値は元のwriteメソッド参照を保持します。が定義された 、オリジナルがオーバーライドされる可能性があります。write_flushwrite

stdout.write = write_flush

stdoutこのコードは、がこのようにインポートされていることを前提としていfrom sys import stdoutます。

于 2017-02-25T21:00:30.460 に答える
3

バッファリングされていない出力を取得する1つの方法は、sys.stderr代わりにを使用するsys.stdoutか、単に呼び出すsys.stdout.flush()ことで、明示的に書き込みを強制的に実行することです。

次の手順を実行すると、印刷されたすべてのものを簡単にリダイレクトできます。

import sys; sys.stdout = sys.stderr
print "Hello World!"

printまたは、特定のステートメントのためだけにリダイレクトするには:

print >>sys.stderr, "Hello World!"

stdoutをリセットするには、次のようにします。

sys.stdout = sys.__stdout__
于 2008-09-20T09:40:13.047 に答える
3

バッファリングされていないファイルを作成し、このファイルをsys.stdoutに割り当てることができます。

import sys 
myFile= open( "a.log", "w", 0 ) 
sys.stdout= myFile

システムが提供するstdoutを魔法のように変更することはできません。OSによってPythonプログラムに提供されるためです。

于 2008-09-20T10:39:09.753 に答える
3

クラッシュせずに動作するバリアント (少なくとも 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)
于 2012-06-30T19:20:08.913 に答える
3

(コメントを投稿しましたが、どういうわけか失われました。それで、もう一度:)

  1. 私が気付いたように、CPython (少なくとも Linux では) は、出力先によって動作が異なります。tty に送られる場合、出力は毎回の後にフラッシュさ\n'
    ます。flush()

  2. 出力バッファリングにわずかに関連して
    います。入力の行を反復処理する場合

    for line in sys.stdin:
    ...

CPythonでのfor の実装は、しばらく入力を収集してから、一連の入力行に対してループ本体を実行します。スクリプトが入力行ごとに出力を書き込もうとしている場合、これは出力バッファリングのように見えるかもしれませんが、実際にはバッチ処理であるため、 などの手法は役に立ちません。興味深いことに、この動作はpypyにはありません。これを回避するには、次を使用できますflush()

while True: line=sys.stdin.readline()
...

于 2013-06-11T14:47:38.087 に答える