web-dev-qa-db-fra.com

Supprimer les appels à imprimer (python)

Est-il possible d'empêcher une fonction d'appeler print?


J'utilise le module pygame.joystick pour un jeu sur lequel je travaille.

J'ai créé un objet pygame.joystick.Joystick et, dans la boucle réelle du jeu, appelez sa fonction membre get_button pour vérifier la saisie de l'utilisateur. La fonction fait tout ce dont j'ai besoin, mais le problème est qu'elle appelle aussi print, ce qui ralentit considérablement le jeu. 

Puis-je bloquer cet appel en print?

39
dmlicht

Python vous permet d'écraser la sortie standard (stdout) avec n'importe quel objet fichier. Cela devrait fonctionner sur plusieurs plates-formes et écrire sur le périphérique null.

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"

Si vous ne souhaitez pas que cette fonction soit imprimée, appelez blockPrint() devant elle et enablePrint() si vous souhaitez qu'elle continue. Si vous souhaitez désactiver all printing, commencez à bloquer en haut du fichier.

53
FakeRainBrigand

Sur la base de la solution @FakeRainBrigand, je propose une solution plus sûre:

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

Ensuite, vous pouvez l'utiliser comme ceci:

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

print("This will be printed as before")

Ceci est beaucoup plus sûr car vous ne pouvez pas oublier de réactiver stdout, ce qui est particulièrement critique lors du traitement des exceptions.

# 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.

Si vous avez oublié la clause finally, aucun de vos appels print n'imprimera plus rien. En utilisant la déclaration with, cela ne peut pas arriver.

Il n'est pas prudent d'utiliser sys.stdout = None, car quelqu'un pourrait appeler des méthodes telles que sys.stdout.write ().

39
Alexander Chzhen

Non, il n'y en a pas, surtout que la majorité de PyGame est écrite en C.

Mais si cette fonction appelle print, il s’agit d’un bogue PyGame et vous devez simplement le signaler.

4
Cat Plus Plus

J'ai eu le même problème, et je ne suis pas venu à une autre solution mais pour rediriger la sortie du programme (je ne sais pas exactement si le spamming se produit sur stdout ou stderr) à /dev/null nirvana. 

En effet, il est open source, mais je n’étais pas assez passionné pour plonger dans les sources pygame - et le processus de construction - afin d’arrêter le spam de débogage. 

MODIFIER : 

Le module pygame.joystick a des appels à printf dans toutes les fonctions qui renvoient les valeurs réelles à Python:

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

Malheureusement, vous devez les commenter et recompiler le tout. Peut-être que le setup.py fourni rendrait cela plus facile que je ne le pensais. Tu pourrais essayer ça ...

2
moooeeeep

Si vous souhaitez bloquer les appels d'impression effectués par une fonction particulière, il existe une solution plus simple utilisant des décorateurs. Définissez le décorateur suivant:

# 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

Ensuite, placez simplement @blockPrinting avant toute fonction. Par exemple:

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

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

Le module que j'ai utilisé imprimé à stderr. La solution dans ce cas serait donc:

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

Comme @Alexander Chzhen l'a suggéré, il serait plus sûr d'utiliser un gestionnaire de contexte que d'appeler deux fonctions qui changent d'état.

Cependant, vous n'avez pas besoin de réimplémenter le gestionnaire de contexte - il est déjà dans la bibliothèque standard. Vous pouvez rediriger stdout (l'objet fichier utilisé par print) avec contextlib.redirect_stdout, ainsi que stderr avec contextlib.redirect_stderr.

import os
import contextlib

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

Une approche complètement différente consisterait à rediriger en ligne de commande. Si vous êtes sous Windows, cela signifie un script batch. Sous Linux, bash. 

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

À moins que vous ne traitiez avec plusieurs processus, ceci devrait fonctionne. Pour les utilisateurs Windows, il peut s’agir des raccourcis que vous créez (menu Démarrer/Bureau).

1
FakeRainBrigand