web-dev-qa-db-ja.com

Python関数呼び出しからstdout出力をキャプチャする方法は?

Pythonオブジェクトに何かをするライブラリを使用しています

_do_something(my_object)
_

それを変更します。その間、いくつかの統計を標準出力に出力します。この情報を把握したいと思います。適切な解決策は、do_something()を変更して関連情報を返すことです。

_out = do_something(my_object)
_

しかし、do_something()の開発者がこの問題に取り組むまでにはしばらく時間がかかります。回避策として、do_something()がstdoutに書き込むものを解析することを考えました。

コード内の2つのポイント間で標準出力をキャプチャするにはどうすればよいですか?

_start_capturing()
do_something(my_object)
out = end_capturing()
_

86
Nico Schlömer

このコンテキストマネージャーを試してください:

_# import StringIO for Python 2 or 3
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO

import sys

class Capturing(list):
    def __enter__(self):
        self._stdout = sys.stdout
        sys.stdout = self._stringio = StringIO()
        return self
    def __exit__(self, *args):
        self.extend(self._stringio.getvalue().splitlines())
        del self._stringio    # free up some memory
        sys.stdout = self._stdout
_

使用法:

_with Capturing() as output:
    do_something(my_object)
_

outputは、関数呼び出しによって出力された行を含むリストになりました。

高度な使用法:

明らかでないかもしれないのは、これを複数回行うことができ、結果が連結されることです。

_with Capturing() as output:
    print 'hello world'

print 'displays on screen'

with Capturing(output) as output:  # note the constructor argument
    print 'hello world2'

print 'done'
print 'output:', output
_

出力:

_displays on screen                     
done                                   
output: ['hello world', 'hello world2']
_

Update:彼らはredirect_stdout()contextlib in Python 3.4(redirect_stderr()と共に)。したがって、_io.StringIO_を使用して同様の結果を得ることができます(ただし、Capturingはリストであり、コンテキストマネージャでもあります)間違いなくより便利です)。

147
kindall

python> = 3.4では、contextlibには redirect_stdout デコレータ。次のように質問に答えるために使用できます。

import io
from contextlib import redirect_stdout

f = io.StringIO()
with redirect_stdout(f):
    do_something(my_object)
out = f.getvalue()

ドキュメント から:

Sys.stdoutを別のファイルまたはファイルのようなオブジェクトに一時的にリダイレクトするためのコンテキストマネージャー。

このツールは、出力がstdoutに組み込まれている既存の関数またはクラスに柔軟性を追加します。

たとえば、help()の出力は通常sys.stdoutに送信されます。出力をio.StringIOオブジェクトにリダイレクトすることにより、その出力を文字列でキャプチャできます。

  f = io.StringIO() 
  with redirect_stdout(f):
      help(pow) 
  s = f.getvalue()

Help()の出力をディスク上のファイルに送信するには、出力を通常のファイルにリダイレクトします。

 with open('help.txt', 'w') as f:
     with redirect_stdout(f):
         help(pow)

Help()の出力をsys.stderrに送信するには:

with redirect_stdout(sys.stderr):
    help(pow)

Sys.stdoutに対するグローバルな副作用は、このコンテキストマネージャーがライブラリコードおよびほとんどのスレッドアプリケーションでの使用に適していないことを意味することに注意してください。また、サブプロセスの出力には影響しません。ただし、これは多くのユーティリティスクリプトにとって有用なアプローチです。

このコンテキストマネージャは再入可能です。

62
ForeverWintr