Stille das Stdout einer Funktion in Python ohne Müll sys.stdout und Wiederherstellung jedes Funktionsaufruf

Gibt es einen Weg in Python, um Stdout zu schweigen, ohne einen Funktionsaufruf wie folgt zu verpacken?

Ursprünglicher defekter Code:

from sys import stdout from copy import copy save_stdout = copy(stdout) stdout = open('trash','w') foo() stdout = save_stdout 

Bearbeiten: Korrigierter Code von Alex Martelli

 import sys save_stdout = sys.stdout sys.stdout = open('trash', 'w') foo() sys.stdout = save_stdout 

So funktioniert es, scheint aber schrecklich ineffizient zu sein. Es muss einen besseren Weg geben. Irgendwelche Ideen?

7 Solutions collect form web for “Stille das Stdout einer Funktion in Python ohne Müll sys.stdout und Wiederherstellung jedes Funktionsaufruf”

Das Zuweisen der stdout Variablen, wie Sie es tun, hat keine Wirkung, unter der Annahme, dass foo print enthält – ein weiteres Beispiel dafür, warum Sie niemals Sachen aus einem Modul importieren sollten (wie Sie hier tun), aber immer ein Modul als Ganz (dann qualifizierte Namen verwenden). Die copy ist übrigens irrelevant. Das richtige Äquivalent Ihres Snippets ist:

 import sys save_stdout = sys.stdout sys.stdout = open('trash', 'w') foo() sys.stdout = save_stdout 

Nun , wenn der Code richtig ist, ist die Zeit, um es eleganter oder schneller zu machen. Zum Beispiel könnten Sie ein in-Memory-Datei-ähnliches Objekt anstelle von Datei 'Trash' verwenden:

 import sys import io save_stdout = sys.stdout sys.stdout = io.BytesIO() foo() sys.stdout = save_stdout 

Für Eleganz ist ein Kontext am besten, zB:

 import contextlib import io import sys @contextlib.contextmanager def nostdout(): save_stdout = sys.stdout sys.stdout = io.BytesIO() yield sys.stdout = save_stdout 

Sobald du diesen Kontext definiert hast, für jeden Block, in dem du kein Stdout willst,

 with nostdout(): foo() 

Mehr Optimierung: Sie müssen nur sys.stdout durch ein Objekt ersetzen, das eine No-OP- write . Beispielsweise:

 import contextlib import sys class DummyFile(object): def write(self, x): pass @contextlib.contextmanager def nostdout(): save_stdout = sys.stdout sys.stdout = DummyFile() yield sys.stdout = save_stdout 

Auf die gleiche Weise wie die vorherige Umsetzung von nostdout . Ich glaube nicht, dass es irgendwie sauberer oder schneller wird ;-).

Warum denkst du, das ist ineffizient? Hast du es getestet ? Übrigens geht es gar nicht, weil du die from ... import Anweisung benutzt hast. Das Ersetzen von sys.stdout ist gut, aber machen Sie keine Kopie und verwenden Sie keine temporäre Datei. Öffnen Sie das Null-Gerät stattdessen:

 import sys import os def foo(): print "abc" old_stdout = sys.stdout sys.stdout = open(os.devnull, "w") try: foo() finally: sys.stdout.close() sys.stdout = old_stdout 

Um nur noch hinzuzufügen, was andere schon gesagt haben, hat Python 3.4 den Kontext-Kontext-Kontext-Kontext konvertiert. Es akzeptiert ein Datei (-ähnliches) Objekt, zu dem die Ausgabe umgeleitet werden soll.

Umleiten auf / dev / null wird die Ausgabe unterdrücken:

 In [11]: def f(): print('noise') In [12]: import os, contextlib In [13]: with open(os.devnull, 'w') as devnull: ....: with contextlib.redirect_stdout(devnull): ....: f() ....: In [14]: 

Diese Lösung kann als Dekorateur angepasst werden:

 import os, contextlib def supress_stdout(func): def wrapper(): with open(os.devnull, 'w') as devnull: with contextlib.redirect_stdout(devnull): func() return wrapper @supress_stdout def f(): print('noise') f() # nothing is printed 

Eine weitere mögliche und gelegentlich nützliche Lösung, die sowohl in Python 2 als auch in 3 arbeiten wird, ist, als Argument zu f und dev / null zu gehen und die Ausgabe mit dem file der print umzuleiten:

 In [14]: def f(target): print('noise', file=target) In [15]: with open(os.devnull, 'w') as devnull: ....: f(target=devnull) ....: In [16]: 

Sie können sogar das target komplett optional machen:

 def f(target=sys.stdout): # Here goes the function definition 

Beachten Sie, müssen Sie

 from __future__ import print_function 

In Python 2

Eine kleine Abänderung von Alex Martellis Antwort …

Hierbei handelt es sich um den Fall, wo man stdout für eine Funktion statt einzelner Anrufe an die Funktion immer unterdrücken möchte.

Wenn foo() viele Male genannt wurde, wäre es besser / einfacher, die Funktion zu verpacken (dekorieren). Auf diese Weise ändern Sie die Definition von foo einmal, anstatt jede Verwendung der Funktion in einer mit-Anweisung zu umhüllen.

 import sys from somemodule import foo class DummyFile(object): def write(self, x): pass def nostdout(func): def wrapper(*args, **kwargs): save_stdout = sys.stdout sys.stdout = DummyFile() func(*args, **kwargs) sys.stdout = save_stdout return wrapper foo = nostdout(foo) 

Chiming in sehr spät zu diesem mit dem, was ich dachte, war eine sauberere Lösung für dieses Problem.

 import sys, traceback class Suppressor(object): def __enter__(self): self.stdout = sys.stdout sys.stdout = self def __exit__(self, type, value, traceback): sys.stdout = self.stdout if type is not None: # Do normal exception handling def write(self, x): pass 

Verwendung:

 with Suppressor(): DoMyFunction(*args,**kwargs) 

Durch die Verallgemeinerung noch mehr, können Sie einen schönen Dekorateur, dass die Einnahme erfassen und sogar zurückgeben können:

 import sys import cStringIO from functools import wraps def mute(returns_output=False): """ Decorate a function that prints to stdout, intercepting the output. If "returns_output" is True, the function will return a generator yielding the printed lines instead of the return values. The decorator litterally hijack sys.stdout during each function execution for ALL THE THREADS, so be careful with what you apply it to and in which context. >>> def numbers(): print "42" print "1984" ... >>> numbers() 42 1984 >>> mute()(numbers)() >>> list(mute(True)(numbers)()) ['42', '1984'] """ def decorator(func): @wraps(func) def wrapper(*args, **kwargs): saved_stdout = sys.stdout sys.stdout = cStringIO.StringIO() try: out = func(*args, **kwargs) if returns_output: out = sys.stdout.getvalue().strip().split() finally: sys.stdout = saved_stdout return out return wrapper return decorator 

Ich glaube nicht, dass es sauberer oder schneller wird !-)

Bah! Ich glaube, ich kann ein bisschen besser machen 😀

 import contextlib, cStringIO, sys @contextlib.contextmanager def nostdout(): '''Prevent print to stdout, but if there was an error then catch it and print the output before raising the error.''' saved_stdout = sys.stdout sys.stdout = cStringIO.StringIO() try: yield except Exception: saved_output = sys.stdout sys.stdout = saved_stdout print saved_output.getvalue() raise sys.stdout = saved_stdout 

Was bekommt, was ich ursprünglich wollte, um die Ausgabe normal zu unterdrücken, aber die unterdrückte Ausgabe zu zeigen, wenn ein Fehler geworfen wurde.

  • Wie teste ich Druckaussagen?
  • Von einem paramiko ssh exec_command kontinuierlich ausgegeben werden
  • Tkinter-Unterprozeß-Sperre GUI und nicht zurückgeben stdout zu Text
  • Wie man einen String von Variablen ohne Leerzeichen in Python (minimal coding!) [Duplicate]
  • Wie kann ich "stdout" zu einem Label-Widget umleiten?
  • Erfassen der Ausgabe aus dem gepufferten StdOut-Programm
  • Senden von Strings zwischen Python Scripts unter Verwendung von Teilprozeß-PIPEs
  • Wie kann ich Stdout und Stderr in Python umleiten?
  • Wie kann ich die Stdout-Ausgabe eines Kinderprozesses erfassen?
  • Python-Unterprozeß mit / usr / bin / time: Wie kann man Timing-Info erfassen, aber ignoriert alle anderen Ausgabe?
  • Wie kann ich die Konsolenprotokollierung in Python deaktivieren und wieder aktivieren?
  • Python ist die beste Programmiersprache der Welt.