Wie blockiere ich Anrufe zum Drucken?

79

Gibt es eine Möglichkeit, den Aufruf einer Funktion zu stoppen print?


Ich benutze das pygame.joystickModul für ein Spiel, an dem ich arbeite.

Ich habe ein pygame.joystick.JoystickObjekt erstellt und in der eigentlichen Schleife des Spiels seine Mitgliedsfunktion aufgerufen get_button, um nach Benutzereingaben zu suchen. Die Funktion macht alles, was ich brauche, aber das Problem ist, dass sie auch aufruft print, was das Spiel erheblich verlangsamt.

Kann ich diesen Anruf blockierenprint ?

dmlicht
quelle

Antworten:

104

Mit Python können Sie die Standardausgabe (stdout) mit jedem Dateiobjekt überschreiben. Dies sollte plattformübergreifend funktionieren und auf das Nullgerät schreiben.

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"

Wenn Sie nicht möchten, dass diese eine Funktion gedruckt wird, rufen Sie blockPrint()vorher auf und enablePrint()wann Sie möchten, dass sie fortgesetzt wird. Wenn Sie den gesamten Druck deaktivieren möchten , beginnen Sie oben in der Datei mit dem Blockieren.

Räuber
quelle
22
Dies scheint den Druck für mich dauerhaft blockiert zu haben. enablePrint stellt es nicht wieder her
Johnny V
10
Diese Lösung stellt das ordnungsgemäße Drucken auf den Jupyter-Zellen nicht wieder her
oski86
1
Ich denke, das zu druckende Argument wird noch ausgewertet, sodass es länger dauert als das Skript, wenn alle Druckzeilen manuell auskommentiert sind.
Funkgesteuert
75

Basierend auf der @ FakeRainBrigand-Lösung schlage ich eine sicherere Lösung vor:

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

Dann können Sie es so verwenden:

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

print("This will be printed as before")

Dies ist viel sicherer, da Sie nicht vergessen können, stdout wieder zu aktivieren, was besonders wichtig ist, wenn Sie Ausnahmen behandeln.

Ohne with

Im folgenden Beispiel werden Druckfunktionen zum Aktivieren / Deaktivieren verwendet, die in der vorherigen Antwort vorgeschlagen wurden.

Stellen Sie sich vor, es gibt einen Code, der eine Ausnahme auslösen kann. Wir mussten finallyAnweisung verwenden, um Drucke auf jeden Fall zu ermöglichen.

try:
    disable_prints()
    something_throwing()
    enable_prints() # This will not help in case of exception
except ValueError as err:
    handle_error(err)
finally:
    enable_prints() # That's where it needs to go.

Wenn Sie die finallyKlausel vergessen haben , würde keiner Ihrer printAnrufe mehr drucken.

Es ist withsicherer, die Anweisung zu verwenden, die sicherstellt, dass die Ausdrucke wieder aktiviert werden.

Hinweis: Die Verwendung ist nicht sicher sys.stdout = None, da jemand Methoden wie aufrufen könntesys.stdout.write()

Alexander Chzhen
quelle
6
Sehr gute Lösung! Ich habe gerade das Gleiche geschrieben und dann festgestellt, dass Sie bereits so geantwortet haben: D Ich werde ein paar Informationen darüber hinzufügen, warum dies ein besserer Weg ist, dies zu tun.
iFreilicht
Noobie-Frage hier: Wäre es wichtig, devnull nach dem Verlassen der Klasse zu schließen?
Jlsecrest
@ Wadsworth, ich weiß die Antwort nicht. Ich denke, Devnulls Eigenschaften erfordern nicht, dass es richtig geschlossen wird. Gerüchten zufolge sollten Sie jedoch immer offene Handler schließen, um Ressourcen freizugeben. CPython sollte, wie ich weiß, devnull selbst schließen, soweit der Garbage Collector es bekommt.
Alexander Chzhen
2
Ich bekam ResourceWarning: unclosed file <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'>bei der Verwendung dieses Codes, löste es durch Setzen von sys.stdout = None anstelle von open (os.devnull, 'w')
WellDone2094
@ WellDone2094, danke. Ich habe sys.stdout.close()die Exit-Methode hinzugefügt . Das sollte helfen. Beachten Sie, sys.stdout = Nonedass dies einen Fehler verursachen kann, da jemand die Methoden von stdout wie aufrufen kann sys.stdout.write().
Alexander Chzhen
28

Wie @Alexander Chzhen vorschlug, wäre die Verwendung eines Kontextmanagers sicherer als das Aufrufen eines Paares von Statusänderungsfunktionen.

Sie müssen den Kontextmanager jedoch nicht erneut implementieren - er befindet sich bereits in der Standardbibliothek. Sie können mit und auch mit umleiten stdout(das printverwendete Dateiobjekt) .contextlib.redirect_stdoutstderrcontextlib.redirect_stderr

import os
import contextlib

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

Wenn Sie Druckaufrufe einer bestimmten Funktion blockieren möchten, gibt es eine übersichtlichere Lösung mit Dekoratoren. Definieren Sie den folgenden Dekorateur:

# 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

Dann einfach @blockPrintingvor jede Funktion stellen. Zum Beispiel:

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

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

Nein, das gibt es nicht, insbesondere, dass die Mehrheit von PyGame in C geschrieben ist.

Wenn diese Funktion print aufruft, liegt ein PyGame-Fehler vor, und Sie sollten ihn nur melden.

Cat Plus Plus
quelle
2

Ich hatte das gleiche Problem und bin nicht zu einer anderen Lösung gekommen, sondern um die Ausgabe des Programms (ich weiß nicht genau, ob das Spam auf stdout oder stderr stattfindet) auf /dev/nullNirvana umzuleiten .

In der Tat ist es Open Source, aber ich war nicht leidenschaftlich genug, um in die pygameQuellen - und den Erstellungsprozess - einzutauchen, um den Debug-Spam irgendwie zu stoppen.

EDIT:

Das pygame.joystickModul hat Aufrufe printfin allen Funktionen, die die tatsächlichen Werte an Python zurückgeben:

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

Leider müssten Sie diese auskommentieren und das Ganze neu kompilieren. Vielleicht setup.pywürde das zur Verfügung gestellte dies einfacher machen als ich dachte. Sie könnten dies versuchen ...

moooeeeep
quelle
2

Ein völlig anderer Ansatz wäre die Umleitung über die Befehlszeile. Wenn Sie unter Windows arbeiten, bedeutet dies ein Batch-Skript. Unter Linux Bash.

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

Dies sollte funktionieren , es sei denn, Sie haben es mit mehreren Prozessen zu tun . Für Windows-Benutzer können dies die Verknüpfungen sein, die Sie erstellen (Startmenü / Desktop).

Räuber
quelle
1

Das Modul, mit dem ich gedruckt habe stderr. Die Lösung in diesem Fall wäre also:

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

Basierend auf der @ Alexander Chzhen-Lösung präsentiere ich hier die Möglichkeit, sie auf eine Funktion anzuwenden, mit der Option, das Drucken zu unterdrücken oder nicht.

    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

Ich hoffe, ich kann meine Lösung unter der Antwort von Alexander als Kommentar hinzufügen, aber ich habe nicht genug (50) Ruf, um dies zu tun.

Quân Hoàng
quelle
0

Sie können eine einfache Umleitung durchführen. Dies scheint viel sicherer zu sein, als mit stdout herumzuspielen, und zieht keine zusätzlichen Bibliotheken ein.

enable_print  = print
disable_print = lambda *x, **y: None

print = disable_print
function_that_has_print_in_it(1)  # nothing is printed

print = enable_print
function_that_has_print_in_it(2)  # printing works again!

Hinweis: Dies funktioniert nur zum Deaktivieren der Funktion print () und würde nicht die gesamte Ausgabe deaktivieren, wenn Sie etwas anderes aufrufen, das eine Ausgabe erzeugt. Zum Beispiel, wenn Sie eine C-Bibliothek aufgerufen haben, die ihre eigene Ausgabe an stdout erstellt hat, oder wenn Sie intput () verwendet haben.

xelf
quelle