関数がprint
を呼び出すのを止める方法はありますか?
作業中のゲームに pygame.joystick
モジュールを使用しています。
pygame.joystick.Joystick
オブジェクトを作成し、ゲームの実際のループでそのメンバー関数get_button
を呼び出してユーザー入力を確認します。この関数は必要なことをすべて行いますが、問題はprint
も呼び出すことであり、これによりゲームがかなり遅くなります。
print
へのこの呼び出しをblockできますか?
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印刷を無効にする場合は、ファイルの先頭からブロックを開始します。
@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
を使用することは安全ではありません。
いいえ、特にありません。PyGameの大部分はCで書かれています。
しかし、この関数がprintを呼び出す場合、それはPyGameのバグであり、報告する必要があります。
@Alexander Chzhenが示唆したように、コンテキストマネージャーを使用する方が、状態を変更する関数のペアを呼び出すよりも安全です。
ただし、コンテキストマネージャを再実装する必要はありません-既に標準ライブラリにあります。 stdout
(print
が使用するファイルオブジェクト)をcontextlib.redirect_stdout
でリダイレクトし、stderr
をcontextlib.redirect_stderr
でリダイレクトすることもできます。
import os
import contextlib
with open(os.devnull, "w") as f, contextlib.redirect_stdout(f):
print("This won't be printed.")
私は同じ問題を抱えており、別の解決策には至りませんでしたが、プログラムの出力(スパムがstdoutまたはstderrで発生するかどうかは正確にわかりません)を/dev/null
nirvanaにリダイレクトしました。
確かに、それはオープンソースですが、私はpygame
ソースとビルドプロセスに飛び込んでデバッグスパムを何らかの形で止めるほど情熱的ではありませんでした。
編集:
pygame.joystick
モジュール には、実際の値をPythonに返すすべての関数でprintf
の呼び出しがあります。
printf("SDL_JoystickGetButton value:%d:\n", value);
残念ながら、これらをコメントアウトして、全体を再コンパイルする必要があります。おそらく、提供されたsetup.py
はこれを思っていたよりも簡単にするでしょう。これを試すことができます...
特定の関数によって行われた印刷呼び出しをブロックする場合は、デコレーターを使用したよりきれいなソリューションがあります。次のデコレータを定義します。
# 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()
使用したモジュールはstderr
に出力されました。したがって、その場合の解決策は次のとおりです。
sys.stdout = open(os.devnull, 'w')
まったく異なるアプローチは、コマンドラインでリダイレクトすることです。 Windowsを使用している場合、これはバッチスクリプトを意味します。 Linuxでは、bash。
/full/path/to/my/game/game.py > /dev/null
C:\Full\Path\To\My\Game.exe > nul
複数のプロセスを扱っていない限り、これはshould動作します。 Windowsユーザーの場合、これは作成しているショートカット(スタートメニュー/デスクトップ)です。
@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
アレクサンダーの回答の下に自分の解決策をコメントとして追加できることを望みますが、そうするのに十分な評判がありません。