Python の contextlib.redirect_stdout で出力先を変える

contextlib.redirect_stdoutredirect_stderr を使うと、標準出力や標準エラー出力の出力先を一時的に変更できます。テストやログ取得、出力のキャプチャに便利です。

redirect_stdout の基本

標準出力をファイルやバッファにリダイレクトします。

from contextlib import redirect_stdout
import io

# StringIO にリダイレクト
f = io.StringIO()
with redirect_stdout(f):
    print("この出力はキャプチャされる")
    print("複数行も OK")

output = f.getvalue()
print(f"キャプチャ結果:\n{output}")

with ブロックを抜けると、標準出力は自動的に元に戻ります。

ファイルへのリダイレクト

出力をファイルに保存することもできます。

from contextlib import redirect_stdout

with open("output.txt", "w") as f:
    with redirect_stdout(f):
        print("この出力はファイルに書き込まれる")
        for i in range(5):
            print(f"Line {i}")

redirect_stderr

標準エラー出力も同様にリダイレクトできます。

from contextlib import redirect_stderr
import io
import sys

f = io.StringIO()
with redirect_stderr(f):
    print("これはエラー出力", file=sys.stderr)

error_output = f.getvalue()
print(f"エラー出力: {error_output}")

両方を同時にリダイレクト

標準出力と標準エラー出力を同時にリダイレクトすることもできます。

from contextlib import redirect_stdout, redirect_stderr
import io
import sys

stdout_buf = io.StringIO()
stderr_buf = io.StringIO()

with redirect_stdout(stdout_buf), redirect_stderr(stderr_buf):
    print("標準出力")
    print("エラー出力", file=sys.stderr)

print(f"stdout: {stdout_buf.getvalue()}")
print(f"stderr: {stderr_buf.getvalue()}")

実用例:関数の出力をキャプチャ

print() を使う関数の出力をキャプチャしてテストできます。

from contextlib import redirect_stdout
import io

def greet(name):
    print(f"Hello, {name}!")
    print("Welcome!")

def test_greet():
    f = io.StringIO()
    with redirect_stdout(f):
        greet("Alice")
    
    output = f.getvalue()
    assert "Hello, Alice!" in output
    assert "Welcome!" in output
    print("テスト成功")

test_greet()

実用例:サードパーティライブラリの出力を抑制

うるさいライブラリの出力を一時的に抑制します。

from contextlib import redirect_stdout, redirect_stderr
import os

# /dev/null (Unix) や NUL (Windows) に捨てる
with open(os.devnull, "w") as devnull:
    with redirect_stdout(devnull), redirect_stderr(devnull):
        # この中の出力は表示されない
        print("これは表示されない")
        noisy_library_function()

出力を抑制するヘルパー

何度も使う場合はヘルパー関数を作ると便利です。

from contextlib import contextmanager, redirect_stdout, redirect_stderr
import os

@contextmanager
def suppress_output():
    with open(os.devnull, "w") as devnull:
        with redirect_stdout(devnull), redirect_stderr(devnull):
            yield

with suppress_output():
    print("これは表示されない")

print("これは表示される")

注意点

リダイレクトは sys.stdout / sys.stderr への書き込みにのみ影響します。C拡張モジュールが直接ファイルディスクリプタに書き込む場合は、この方法ではキャプチャできません。

# Python の print() → キャプチャできる
# C拡張の直接出力 → キャプチャできない場合がある

テストやログ取得で redirect_stdout を活用すると、出力に依存した処理を柔軟に制御できます。