web-dev-qa-db-ja.com

印刷の呼び出しを抑制する(python)

関数がprintを呼び出すのを止める方法はありますか?


作業中のゲームに pygame.joystick モジュールを使用しています。

pygame.joystick.Joystickオブジェクトを作成し、ゲームの実際のループでそのメンバー関数get_buttonを呼び出してユーザー入力を確認します。この関数は必要なことをすべて行いますが、問題はprintも呼び出すことであり、これによりゲームがかなり遅くなります。

printへのこの呼び出しをblockできますか?

48
dmlicht

Pythonでは、標準出力(stdout)を任意のファイルオブジェクトで上書きできます。これはクロスプラットフォームで動作し、ヌルデバイスに書き込む必要があります。

_import sys, os

# Disable
def blockPrint():
    sys.stdout = open(os.devnull, 'w')

# Restore
def enablePrint():
    sys.stdout = sys.__stdout__


print 'This will print'

blockPrint()
print "This won't"

enablePrint()
print "This will too"
_

その1つの関数を印刷したくない場合は、その前にblockPrint()を呼び出し、続行する場合はenablePrint()を呼び出します。 all印刷を無効にする場合は、ファイルの先頭からブロックを開始します。

64
Brigand

@FakeRainBrigandソリューションに基づいて、より安全なソリューションを提案しています。

import os, sys

class HiddenPrints:
    def __enter__(self):
        self._original_stdout = sys.stdout
        sys.stdout = open(os.devnull, 'w')

    def __exit__(self, exc_type, exc_val, exc_tb):
        sys.stdout.close()
        sys.stdout = self._original_stdout

その後、次のように使用できます。

with HiddenPrints():
    print("This will not be printed")

print("This will be printed as before")

これは、stdoutを再度有効にすることを忘れることができないため、はるかに安全です。これは、例外を処理するときに特に重要です。

# This is an example of not-so-good solution
# without 'with' context manager statement.
try:
    disable_prints()
    something_throwing()
    # enable_prints() This wouldn't be enough!
except ValueError:
    handle_error()
finally:
    enable_prints() # That's where it needs to go.

finally句を忘れた場合、print呼び出しはどれも表示しなくなります。 withステートメントを使用すると、それは起こりえません。

誰かがsys.stdout.write()のようなメソッドを呼び出すことができるため、sys.stdout = Noneを使用することは安全ではありません。

49

いいえ、特にありません。PyGameの大部分はCで書かれています。

しかし、この関数がprintを呼び出す場合、それはPyGameのバグであり、報告する必要があります。

4
Cat Plus Plus

@Alexander Chzhenが示唆したように、コンテキストマネージャーを使用する方が、状態を変更する関数のペアを呼び出すよりも安全です。

ただし、コンテキストマネージャを再実装する必要はありません-既に標準ライブラリにあります。 stdoutprintが使用するファイルオブジェクト)をcontextlib.redirect_stdoutでリダイレクトし、stderrcontextlib.redirect_stderrでリダイレクトすることもできます。

import os
import contextlib

with open(os.devnull, "w") as f, contextlib.redirect_stdout(f):
    print("This won't be printed.")
4

私は同じ問題を抱えており、別の解決策には至りませんでしたが、プログラムの出力(スパムがstdoutまたはstderrで発生するかどうかは正確にわかりません)を/dev/null nirvanaにリダイレクトしました。

確かに、それはオープンソースですが、私はpygameソースとビルドプロセスに飛び込んでデバッグスパムを何らかの形で止めるほど情熱的ではありませんでした。

編集:

pygame.joystickモジュール には、実際の値をPythonに返すすべての関数でprintfの呼び出しがあります。

printf("SDL_JoystickGetButton value:%d:\n", value);

残念ながら、これらをコメントアウトして、全体を再コンパイルする必要があります。おそらく、提供されたsetup.pyはこれを思っていたよりも簡単にするでしょう。これを試すことができます...

2
moooeeeep

特定の関数によって行われた印刷呼び出しをブロックする場合は、デコレーターを使用したよりきれいなソリューションがあります。次のデコレータを定義します。

# decorater used to block function printing to the console
def blockPrinting(func):
    def func_wrapper(*args, **kwargs):
        # block all printing to the console
        sys.stdout = open(os.devnull, 'w')
        # call the method in question
        value = func(*args, **kwargs)
        # enable all printing to the console
        sys.stdout = sys.__stdout__
        # pass the return value of the method back
        return value

    return func_wrapper

次に、@blockPrinting関数の前。例えば:

# This will print
def helloWorld():
    print("Hello World!")
helloWorld()

# This will not print
@blockPrinting
def helloWorld2():
    print("Hello World!")
helloWorld2()
2
Fowler

使用したモジュールはstderrに出力されました。したがって、その場合の解決策は次のとおりです。

sys.stdout = open(os.devnull, 'w')
1
David Nathan

まったく異なるアプローチは、コマンドラインでリダイレクトすることです。 Windowsを使用している場合、これはバッチスクリプトを意味します。 Linuxでは、bash。

/full/path/to/my/game/game.py > /dev/null
C:\Full\Path\To\My\Game.exe > nul

複数のプロセスを扱っていない限り、これはshould動作します。 Windowsユーザーの場合、これは作成しているショートカット(スタートメニュー/デスクトップ)です。

1
Brigand

@Alexander Chzhenソリューションに基づいて、印刷を抑制するかどうかを選択するオプションを使用して、関数に適用する方法を示します。

    import os, sys
    class SuppressPrints:
        #different from Alexander`s answer
        def __init__(self, suppress=True):
            self.suppress = suppress

        def __enter__(self):
            if self.suppress:
                self._original_stdout = sys.stdout
                sys.stdout = open(os.devnull, 'w')

        def __exit__(self, exc_type, exc_val, exc_tb):
            if self.suppress:
                sys.stdout.close()
                sys.stdout = self._original_stdout
    #implementation
    def foo(suppress=True):
        with SuppressPrints(suppress):
            print("It will be printed, or not")

    foo(True)  #it will not be printed
    foo(False) #it will be printed

アレクサンダーの回答の下に自分の解決策をコメントとして追加できることを望みますが、そうするのに十分な評判がありません。

0
Quân Hoàng