¿Cómo imprimir a stderr en Python?

Hay varias formas de escribir a stderr:

# Note: this first one does not work in Python 3 print >> sys.stderr, "spam" sys.stderr.write("spam\n") os.write(2, b"spam\n") from __future__ import print_function print("spam", file=sys.stderr) 

Eso parece contradecir el zen de Python # 13 , así que ¿cuál es la diferencia aquí y hay ventajas o desventajas de una manera u otra? ¿Qué camino se debe utilizar?

Debe haber una, y preferiblemente solo una, manera obvia de hacerlo.

Descubrí que este es el único legible + corto + flexible + portátil +:

 from __future__ import print_function import sys def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) 

La función eprint se puede utilizar de la misma manera que la función de print estándar:

 >>> print("Test") Test >>> eprint("Test") Test >>> eprint("foo", "bar", "baz", sep="---") foo---bar---baz 
 import sys sys.stderr.write() 

Es mi elección, solo es más legible y dice exactamente lo que pretende hacer y es portátil en todas las versiones.

Edición: ser ‘pythonic’ es un tercer pensamiento para mí sobre la legibilidad y el rendimiento … con estas dos cosas en mente, con python, el 80% de su código será pythonic. La comprensión de la lista es la “gran cosa” que no se usa tan a menudo (legibilidad).

Para Python 2, mi elección es: print >> sys.stderr, 'spam' ya que simplemente puede imprimir listas / dados, etc. sin convertirlo en una cadena. print >> sys.stderr, {'spam': 'spam'} lugar de: sys.stderr.write(str({'spam': 'spam'}))

print >> sys.stderr se ha ido en Python3. http://docs.python.org/3.0/whatsnew/3.0.html dice:

 Old: print >>sys.stderr, "fatal error" New: print("fatal error", file=sys.stderr) 

Desafortunadamente, esto es bastante feo. Alternativamente, use

 sys.stderr.write("fatal error\n") 

pero tenga en cuenta que write no es un reemplazo 1: 1 para print .

Nadie ha mencionado el logging todavía, pero el registro se creó específicamente para comunicar mensajes de error. Por defecto está configurado para escribir en stderr. Este script:

 # foo.py import logging logging.basicConfig(format='%(message)s') logging.warning('I print to stderr by default') logging.info('For this you must change the level and add a handler.') print('hello world') 

tiene el siguiente resultado cuando se ejecuta en la línea de comando:

 $ python3 foo.py > bar.txt I print to stderr by default 

(y bar.txt contiene el ‘hola mundo’)

(Tenga en cuenta que logging.warn ha quedado en desuso , use logging.warning en logging.warning lugar)

Yo diría que su primer acercamiento:

 print >> sys.stderr, 'spam' 

es la “Una …. manera obvia de hacerlo”. Las otras no cumplen con la regla # 1 (“Lo bello es mejor que lo feo”).

Hice lo siguiente usando Python 3:

 from sys import stderr def print_err(*args, **kwargs): print(*args, file=stderr, **kwargs) 

Así que ahora puedo agregar argumentos de palabras clave, por ejemplo, para evitar el retorno de carro:

 print_err("Error: end of the file reached. The word ", end='') print_err(word, "was not found") 

Esto imitará la función de impresión estándar pero se imprimirá en stderr

 def print_err(*args): sys.stderr.write(' '.join(map(str,args)) + '\n') 

EDITAR En retrospectiva, creo que la posible confusión con el cambio de sys.stderr y no ver el comportamiento actualizado hace que esta respuesta no sea tan buena como usar una función simple como otros han señalado.

Usando parcial solo te guarda 1 línea de código. La confusión potencial no vale la pena guardar 1 línea de código.

original

Para hacerlo aún más fácil, aquí hay una versión que usa ‘parcial’, que es una gran ayuda para envolver funciones.

 from __future__ import print_function import sys from functools import partial error = partial(print, file=sys.stderr) 

Entonces lo usas como tal

 error('An error occured!') 

Puede verificar que se está imprimiendo en stderr y no en stdout haciendo lo siguiente (código de superposición desde http://coreygoldberg.blogspot.com.au/2009/05/python-redirect-or-turn-off-stdout-and .html ):

 # over-ride stderr to prove that this function works. class NullDevice(): def write(self, s): pass sys.stderr = NullDevice() # we must import print error AFTER we've removed the null device because # it has been assigned and will not be re-evaluated. # assume error function is in print_error.py from print_error import error # no message should be printed error("You won't see this error!") 

La desventaja de esto es que parcial asigna el valor de sys.stderr a la función envuelta en el momento de la creación. Lo que significa que, si redirige stderr más tarde, no afectará a esta función. Si planea redireccionar stderr, use el método ** kwargs mencionado por aaguirre en esta página.

Lo mismo se aplica a stdout:

 print 'spam' sys.stdout.write('spam\n') 

Como se indicó en las otras respuestas, la impresión ofrece una interfaz bonita que suele ser más conveniente (por ejemplo, para imprimir información de depuración), mientras que la escritura es más rápida y también puede ser más conveniente cuando tiene que formatear la salida exactamente de cierta manera. También consideraría la mantenibilidad:

  1. Más tarde puede decidir cambiar entre stdout / stderr y un archivo normal.

  2. La syntax de print () ha cambiado en Python 3, por lo que si necesita admitir ambas versiones, write () podría ser mejor.

Estoy trabajando en python 3.4.3. Estoy cortando un poco de escritura que muestra cómo llegué aquí:

 [18:19 jsilverman@JSILVERMAN-LT7 pexpect]$ python3 >>> import sys >>> print("testing", file=sys.stderr) testing >>> [18:19 jsilverman@JSILVERMAN-LT7 pexpect]$ 

¿Funcionó? Intente redirigir stderr a un archivo y vea qué sucede:

 [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$ python3 2> /tmp/test.txt >>> import sys >>> print("testing", file=sys.stderr) >>> [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$ [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$ cat /tmp/test.txt Python 3.4.3 (default, May 5 2015, 17:58:45) [GCC 4.9.2] on cygwin Type "help", "copyright", "credits" or "license" for more information. testing [18:22 jsilverman@JSILVERMAN-LT7 pexpect]$ 

Bueno, aparte del hecho de que la pequeña introducción que Python te da ha sido introducida en stderr (¿a dónde más iría?), Funciona.

Si haces una prueba simple:

 import time import sys def run1(runs): x = 0 cur = time.time() while x < runs: x += 1 print >> sys.stderr, 'X' elapsed = (time.time()-cur) return elapsed def run2(runs): x = 0 cur = time.time() while x < runs: x += 1 sys.stderr.write('X\n') sys.stderr.flush() elapsed = (time.time()-cur) return elapsed def compare(runs): sum1, sum2 = 0, 0 x = 0 while x < runs: x += 1 sum1 += run1(runs) sum2 += run2(runs) return sum1, sum2 if __name__ == '__main__': s1, s2 = compare(1000) print "Using (print >> sys.stderr, 'X'): %s" %(s1) print "Using (sys.stderr.write('X'),sys.stderr.flush()):%s" %(s2) print "Ratio: %f" %(float(s1) / float(s2)) 

¡Encontrará que sys.stderr.write () es consistentemente 1.81 veces más rápido!

Tratar:

 from sys import stderr print >> sys.stderr, 'spam' 

La respuesta a la pregunta es: hay diferentes maneras de imprimir stderr en python, pero eso depende de 1.) qué versión de python estamos usando 2.) qué resultado exacto queremos.

La diferencia entre la impresión y la función de escritura de stderr : stderr : stderr (error estándar) es una canalización integrada en cada sistema UNIX / Linux, cuando su progtwig falla e imprime información de depuración (como un rastreo en Python), va al stderr tubo.

print : print es un contenedor que formatea las entradas (la entrada es el espacio entre el argumento y la nueva línea al final) y luego llama a la función de escritura de un objeto dado, el objeto dado por defecto es sys.stdout, pero podemos pasar un archivo, es decir, podemos imprimir la entrada en un archivo también.

Python2: Si estamos usando python2 entonces

 >>> import sys >>> print "hi" hi >>> print("hi") hi >>> print >> sys.stderr.write("hi") hi 

La coma al final de Python2 se ha convertido en un parámetro en Python3, por lo que si usamos comas al final para evitar la nueva línea después de una impresión, en Python3 parecerá una impresión (‘Text to print’, end = ”), que es un error de syntax en Python2 .

http://python3porting.com/noconv.html

Si comprobamos lo mismo arriba sceario en python3:

 >>> import sys >>> print("hi") hi 

Bajo Python 2.6 hay una importación futura para hacer la impresión en una función. Por lo tanto, para evitar errores de syntax y otras diferencias, deberíamos iniciar cualquier archivo en el que usemos print () con la función de importación de impresión futura . La importación futura solo funciona con Python 2.6 y versiones posteriores, por lo que para Python 2.5 y versiones anteriores tiene dos opciones. Puede convertir la impresión más compleja en algo más simple, o puede usar una función de impresión independiente que funcione tanto con Python2 como con Python3.

 >>> from __future__ import print_function >>> >>> def printex(*args, **kwargs): ... print(*args, file=sys.stderr, **kwargs) ... >>> printex("hii") hii >>> 

Caso: debe señalarse que sys.stderr.write () o sys.stdout.write () (stdout (salida estándar) es una canalización que está integrada en todos los sistemas UNIX / Linux) no es un reemplazo para la impresión, pero sí Podemos usarlo como alternativa en algún caso. Imprimir es un contenedor que envuelve la entrada con espacio y nueva línea al final y utiliza la función de escritura para escribir. Esta es la razón por la que sys.stderr.write () es más rápido.

Nota: también podemos rastrear y depurar utilizando el registro.

 #test.py import logging logging.info('This is the existing protocol.') FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s" logging.basicConfig(format=FORMAT) d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} logging.warning("Protocol problem: %s", "connection reset", extra=d) 

https://docs.python.org/2/library/logging.html#logger-objects

En Python 3, uno puede usar print ():

 print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) 

casi fuera de la caja:

 import sys print("Hello, world!", file=sys.stderr) 

o:

 from sys import stderr print("Hello, world!", file=stderr) 

Esto es sencillo y no necesita incluir nada más que sys.stderr .

 import logging logging.basicConfig(format='[%(levelname)s] %(message)s') logging.error('is error, alarm!') logging.warning('is simple waring') print('hello') 

registro pydoc