Pythonでstdoutを「nothing」にリダイレクトする


128

十分な数のモジュールで構成される大きなプロジェクトがあり、それぞれが標準出力に何かを出力しています。現在、プロジェクトの規模が大きくなっているため、規模は大きくありません。printかなり遅いプログラムを作ったのstdうちに多くのことを印刷するステートメント。

そこで、実行時に標準出力に何かを出力するかどうかを決定したいと思います。モジュールがたくさんあるので、モジュールを変更することはできません。(私はstdoutをファイルにリダイレクトできることを知っていますが、これでもかなり遅いです。)

だから私の質問は、どのようにstdoutを何にもリダイレクトprintしないことです。

# I want to do something like this.
sys.stdout = None         # this obviously will give an error as Nonetype object does not have any write method.

現在私が持っている唯一のアイデアは、writeメソッド(何もしない)を持つクラスを作成し、stdoutをこのクラスのインスタンスにリダイレクトすることです。

class DontPrint(object):
    def write(*args): pass

dp = DontPrint()
sys.stdout = dp

これにはPythonに組み込みのメカニズムがありますか?それともこれより良いものはありますか?



1
ちょっと変わったことを発見しました。sys.stdoutをNoneに変換すると、実際には私のプログラムで機能しますが、理由はわかりません。私はos.devnullへのエンコーディングリダイレクトで本当に奇妙な問題を抱えていたので、Noneだけを使用してみましたが、うまくいきました。Djangoユニットテストでそれを行うことと何か関係があるかもしれませんが、私にはわかりません。
Teekin

回答:


233

クロスプラットフォーム:

import os
import sys
f = open(os.devnull, 'w')
sys.stdout = f

Windowsの場合:

f = open('nul', 'w')
sys.stdout = f

Linuxの場合:

f = open('/dev/null', 'w')
sys.stdout = f

それをどのようにキャンセルしますか?終了後に印刷ステートメントをオンに戻す方法はありますか?
jj172 2014

4
確かに、元のファイルへの参照を保存し、sys.stdout後で元に戻すだけです。たとえばold_stdout = sys.stdout、他のどのコードの前でも、sys.stdout = old_stdout完了したら。
Andrew Clark、

1
注:ファイル記述子レベルではリダイレクトしません。つまり、外部の子プロセスの出力、Cの標準出力に直接出力するC拡張からの出力のリダイレクトに失敗する可能性があります。 os.write(1, b'abc\n')。あなたは必要なos.dup2()参照、ファイルディスクリプタ・レベルでリダイレクトするには、stdout_redirected()
JFS

4
sys.__stdout__リダイレクトをキャンセルするためのものがあることに注意してください。したがってsys.stdout = sys.__stdout__、バックアップを保存する必要はありません。
コンスタンティンSekeresh

28

これを行うための良い方法は、印刷をラップする小さなコンテキストプロセッサを作成することです。次に、with-を使用してすべての出力を無音にします。

Python 2:

import os
import sys
from contextlib import contextmanager

@contextmanager
def silence_stdout():
    old_target = sys.stdout
    try:
        with open(os.devnull, "w") as new_target:
            sys.stdout = new_target
            yield new_target
    finally:
        sys.stdout = old_target

with silence_stdout():
    print("will not print")

print("this will print")

Python 3.4以降:

Python 3.4には、このような組み込みのコンテキストプロセッサがあるため、次のように単純にcontextlibを使用できます。

import contextlib

with contextlib.redirect_stdout(None):
    print("will not print")

print("this will print")

このコードを実行すると、1行目ではなく2行目の出力のみが出力されます。

$ python test.py
this will print

これはクロスプラットフォーム(Windows + Linux + Mac OSX)で機能し、他の答えよりもきれいです。


@celticminstrel正解です。訂正してくれてありがとう。後でsys.stdoutをリセットするようにコードを更新しました。
EmilStenström2016

これにはいくつかのエラーチェックがありませんが、すばらしいアイデアです
Mad Physicist

Python 3でもこれがどのように機能するかを示すコードを追加しました。
EmilStenström

15

Python 3.4以降を使用している場合は、標準ライブラリを使用したシンプルで安全なソリューションがあります。

import contextlib

with contextlib.redirect_stdout(None):
  print("This won't print!")

3
with contextlib.redirect_stdout(None)同様に動作します
クリスコグドン2018

@ChrisCogdon非常に良いヒント、それに応じて答えを編集しました。
iFreilicht 2018

1
pprintライブラリを使用している場合は機能しません。AttributeError: 'NoneType' object has no attribute 'write'
Speeeddy

@Speeeddy Python 2でこのエラーが発生しましたか?write何もしないダミーメソッドでクラスを作成できます。以下の私の答えを参照してください。
dizcza

8

(少なくとも私のシステムでは)os.devnullへの書き込みは、DontPrintクラスへの書き込みよりも約5倍速いようです。

#!/usr/bin/python
import os
import sys
import datetime

ITER = 10000000
def printlots(out, it, st="abcdefghijklmnopqrstuvwxyz1234567890"):
   temp = sys.stdout
   sys.stdout = out
   i = 0
   start_t = datetime.datetime.now()
   while i < it:
      print st
      i = i+1
   end_t = datetime.datetime.now()
   sys.stdout = temp
   print out, "\n   took", end_t - start_t, "for", it, "iterations"

class devnull():
   def write(*args):
      pass


printlots(open(os.devnull, 'wb'), ITER)
printlots(devnull(), ITER)

次の出力を与えました:

<open file '/dev/null', mode 'wb' at 0x7f2b747044b0> 
   took 0:00:02.074853 for 10000000 iterations
<__main__.devnull instance at 0x7f2b746bae18> 
   took 0:00:09.933056 for 10000000 iterations

4
記録のために、次回何かを時間を計り
Antoine Pelisse

6

Unix環境(Linuxを含む)の場合、出力を/dev/null次のようにリダイレクトできます。

python myprogram.py > /dev/null

Windowsの場合:

python myprogram.py > nul

2
すべてのプラットフォームで機能するソリューションを用意することをお勧めします。
Pushpak Dagade、2011

2
@Guanidene、おそらく、彼が彼のプログラムを使用している唯一の人物である場合、彼は環境をかなり保証することができます。
Nick Radford

nul = myfunc()
Hicsy

2

これはどう:

from contextlib import ExitStack, redirect_stdout
import os

with ExitStack() as stack:
    if should_hide_output():
        null_stream = open(os.devnull, "w")
        stack.enter_context(null_stream)
        stack.enter_context(redirect_stdout(null_stream))
    noisy_function()

これは、 contextlibモジュールのて、の結果に応じて、実行しようとしているコマンドの出力を非表示にし、should_hide_output()その関数の実行後に出力動作を復元します。

標準エラー出力を非表示にする場合は、インポートします redirect_stderrcontextlibて、という行を追加しますstack.enter_context(redirect_stderr(null_stream))

主な欠点は、これがPython 3.4以降のバージョンでのみ機能することです。



1

クラスは問題なく動作します(write()メソッド名を除いてwrite()、小文字で呼び出す必要があります)。のコピーをsys.stdout別の変数に保存してください。

* NIXを使用している場合は実行できますsys.stdout = open('/dev/null')が、これは独自のクラスをロールするよりも移植性が低くなります。



0

これを試してみませんか?

sys.stdout.close()
sys.stderr.close()

A)機能しない場合もあり、B)機能する場合、出力を抑制するだけでなく、エラーが発生するためです。
マッド

0
sys.stdout = None

print()ケースには問題ありません。ただし、sys.stdoutのメソッド(例:)を呼び出すと、エラーが発生する可能性がありますsys.stdout.write()

ドキュメントにメモがあります:

状況によっては、stdin、stdout、stderr、および元の値stdinstdoutstderrがNoneになる場合があります。通常、コンソールに接続されていないWindows GUIアプリと、pythonwで始まるPythonアプリが該当します。


この場合、「OK」と「印刷しようとしてもエラーになりません」はまったく異なります。
マッド

1
あなたが正しい。でメソッドを呼び出すことができないsys.stdout = Nullので、危険な場合があります。
Alexander Chzhen

この正確なケースでは、危険であることが知られています。OPは、彼がそれを行うことから得るエラーに特に対処します。
マッド

0

iFreilichtの回答の補足-python 2と3の両方で機能します。

import sys

class NonWritable:
    def write(self, *args, **kwargs):
        pass

class StdoutIgnore:
    def __enter__(self):
        self.stdout_saved = sys.stdout
        sys.stdout = NonWritable()
        return self

    def __exit__(self, *args):
        sys.stdout = self.stdout_saved

with StdoutIgnore():
    print("This won't print!")
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.