Redirigiendo stdout a "nada" en python
python-2.7 (10)
Tengo un proyecto grande que consiste en una cantidad suficientemente grande de módulos, cada uno imprimiendo algo para la salida estándar. Ahora que el proyecto ha crecido en tamaño, hay un gran no. de print
declaraciones de print
que imprimen mucho en el estándar que ha hecho que el programa sea considerablemente más lento.
Entonces, ahora quiero decidir en tiempo de ejecución si imprimir o no algo en el stdout. No puedo hacer cambios en los módulos ya que hay muchos. (Sé que puedo redirigir el stdout a un archivo, pero incluso esto es considerablemente lento).
Entonces mi pregunta es ¿cómo puedo redirigir el stdout a nada, es decir, cómo hago que la declaración de print
no haga nada?
# I want to do something like this.
sys.stdout = None # this obviously will give an error as Nonetype object does not have any write method.
Actualmente, la única idea que tengo es hacer una clase que tenga un método de escritura (que no haga nada) y redireccionar el stdout a una instancia de esta clase.
class DontPrint(object):
def write(*args): pass
dp = DontPrint()
sys.stdout = dp
¿Hay un mecanismo incorporado en Python para esto? ¿O hay algo mejor que esto?
¿Por qué no pruebas esto?
sys.stdout.close()
sys.stderr.close()
(al menos en mi sistema) parece que escribir en os.devnull es aproximadamente 5 veces más rápido que escribir en una clase DontPrint, es decir,
#!/usr/bin/python
import os
import sys
import datetime
ITER = 10000000
def printlots(out, it, st="abcdefghijklmnopqrstuvwxyz1234567890"):
temp = sys.stdout
sys.stdout = out
i = 0
start_t = datetime.datetime.now()
while i < it:
print st
i = i+1
end_t = datetime.datetime.now()
sys.stdout = temp
print out, "/n took", end_t - start_t, "for", it, "iterations"
class devnull():
def write(*args):
pass
printlots(open(os.devnull, ''wb''), ITER)
printlots(devnull(), ITER)
dio el siguiente resultado:
<open file ''/dev/null'', mode ''wb'' at 0x7f2b747044b0>
took 0:00:02.074853 for 10000000 iterations
<__main__.devnull instance at 0x7f2b746bae18>
took 0:00:09.933056 for 10000000 iterations
En su próximo proyecto, use el módulo de registro en lugar de imprimir basura en stdout / stderr.
Multiplataforma:
import os
import sys
f = open(os.devnull, ''w'')
sys.stdout = f
En Windows:
f = open(''nul'', ''w'')
sys.stdout = f
En Linux:
f = open(''/dev/null'', ''w'')
sys.stdout = f
Qué tal esto:
from contextlib import ExitStack, redirect_stdout
import os
with ExitStack() as stack:
if should_hide_output():
null_stream = open(os.devnull, "w")
stack.enter_context(null_stream)
stack.enter_context(redirect_stdout(null_stream))
noisy_function()
Utiliza las funciones del módulo contextlib para ocultar el resultado de cualquier comando que intente ejecutar, según el resultado de should_hide_output()
, y luego restablece el comportamiento de salida una vez que la función se ejecuta.
Si desea ocultar la salida de error estándar, importe redirect_stderr
desde contextlib
y agregue una línea que diga stack.enter_context(redirect_stderr(null_stream))
.
La desventaja principal es que esto solo funciona en Python 3.4 y versiones posteriores.
Si estás en Python 3.4 o superior, hay una solución simple y segura usando la biblioteca estándar:
import contextlib
import os
with contextlib.redirect_stdout(None):
print("This won''t print!")
Si se encuentra en un entorno Unix (Linux incluido), puede redireccionar la salida a /dev/null
:
python myprogram.py > /dev/null
Y para Windows:
python myprogram.py > nul
Su clase funcionará muy bien (con la excepción del nombre del método write()
; debe llamarse write()
, minúscula). Solo asegúrate de guardar una copia de sys.stdout
en otra variable.
Si está en un * NIX, puede hacer sys.stdout = open(''/dev/null'')
, pero esto es menos portátil que rodar su propia clase.
Una buena forma de hacerlo es crear un pequeño procesador de contexto en el que envuelva sus impresiones. Luego, simplemente use está en una with
-statement para silenciar todo el resultado.
import os
import sys
from contextlib import contextmanager
@contextmanager
def silence_stdout():
new_target = open(os.devnull, "w")
old_target, sys.stdout = sys.stdout, new_target
try:
yield new_target
finally:
sys.stdout = old_target
with silence_stdout():
print("will not print")
print("this will print")
Al ejecutar este código solo se imprime la segunda línea de salida, no la primera:
$ python test.py
this will print
Esto funciona multiplataforma (Windows + Linux + Mac OSX) y es más limpio que las otras respuestas.
sys.stdout = None
¡Está totalmente bien!
Hay una nota en los documentos :
En algunas condiciones stdin, stdout y stderr, así como los valores originales stdin , stdout y stderr pueden ser None. Suele ser el caso de las aplicaciones de Windows GUI que no están conectadas a una consola y las aplicaciones de Python que se iniciaron con pythonw.
He respondido una pregunta similar here .