¿Cómo imprimir en stderr en Python?

1340

Hay varias formas de escribir en 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 , entonces, ¿cuál es la diferencia aquí y hay ventajas o desventajas de una forma u otra? ¿Qué camino se debe usar?

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

wim
fuente
46
La primera forma en la lista es una de las muchas cosas eliminadas en Python 3. El consenso parece ser que la sintaxis >> era fea de todos modos, y dado que imprimir ahora es una función, la sintaxis nunca funcionaría.
Steve Howard
24
Uso: sys.exit ('Error: <error text>')
marcado el
1
solo usa print.
PythonMaster202

Respuestas:

1165

Encontré que este es el único corto + flexible + portátil + legible:

from __future__ import print_function
import sys

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

La función eprintse puede usar de la misma manera que la printfunción estándar :

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
Marzo
fuente
29
Solo un pensamiento: dado que esto importará la función de impresión, todas las demás "imprimir" en el script original ahora tendrán que "funcionalizarse" agregando "(" y ")". Eso es un pequeño golpe contra este método, OMI.
Dan H
46
@DanH Sí, esto te obliga a preparar tu código para Python3. ¡Supongo que esta podría ser la razón por la que a muchas personas les gusta!
MarcH
18
@MarkH ... sí, te obliga a hacer que tu código esté preparado para Python3 ... también te obliga a hacerlo AHORA, solo para imprimir información de depuración en el stderr ... lo cual me resultaría más complicado La mayoría de las situaciones cuando intento depurar algo. (¡Prefiero no introducir nuevos errores de sintaxis!) :-)
Dan H
30
FWIW este código no te obliga a usar la versión de función de printen todo tu programa. Solo en el módulo que contiene la definición de eprint(). Póngalo en un archivo pequeño por sí mismo, impórtelo eprinten sus otros archivos y puede continuar usando la declaración todo el printtiempo que desee.
alexis
44
Además, la conversión de la función de impresión a impresión es un simple reemplazo de búsqueda que 2to3 ya automatiza para usted. Solo hazlo si no lo has hecho; python2 desaparecerá en menos de 2 años ... Algunas cosas entre 2 y 3 pueden ser un poco complicadas; La función de impresión no es una de ellas. Ver docs.python.org/2/library/2to3.html
bobpaul
548
import sys
sys.stderr.write()

Es mi elección, simplemente más legible y decir exactamente lo que pretendes hacer y portátil en todas las versiones.

Editar: ser 'pitón' 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á pitónico. la comprensión de la lista es la "gran cosa" que no se usa con tanta frecuencia (legibilidad).

Mike Ramirez
fuente
88
Simplemente no te olvides de ruborizar.
temoto
10
La ventaja de la printdeclaración es la impresión sencilla de valores sin cadenas, sin tener que convertirlos primero. Si necesita una declaración impresa, por lo tanto, recomendaría usar la tercera opción para estar preparado para Python 3
vdboor el
56
sys.stderr.write()nada como print. No agrega una nueva línea.
Coronel Panic
41
@temoto - stderr no está protegido, por lo que no es necesario descargarlo.
Matt
11
@SkipHuffman Quieres decir os.linesep. Se trata de stderrque estamos hablando, después de todo. No quiero que la consola se equivoque con la nueva línea incorrecta.
jpmc26
182

print >> sys.stderrse 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)

Para muchos de nosotros, parece algo poco natural relegar el destino al final del comando. La alternativa

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

se ve más orientado a objetos, y va elegantemente de lo genérico a lo específico. Pero tenga en cuenta que writeno es un reemplazo 1: 1 para print.

Joachim W
fuente
66
Supongo que es una cuestión de preferencia, pero no veo de qué se trata print('spam', file=sys.stderr). Si lo está haciendo una y otra vez, puede codificar la función 'eprint' como en la respuesta más popular, pero en ese caso, preguntaría, ¿qué hay de malo en el registro? stackoverflow.com/a/41304513/1450294
Michael Scheper el
1
Otra forma de clarificar la intención sería hacer with sys.stderr as dest:antes una llamada sangría aprint("ERROR", file=dest)
MarkHu
131

Nadie lo ha mencionado loggingtodavía, pero el registro se creó específicamente para comunicar mensajes de error. La configuración básica configurará un controlador de flujo que escriba en stderr.

Este guión:

# foo.py
import logging

logging.basicConfig(format='%(message)s')
log = logging.getLogger(__name__)
log.warning('I print to stderr by default')
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 contendrá el 'hola mundo' impreso en stdout.

sentimentaloide
fuente
3
En mi experiencia, más personas usan la impresión para registrar mensajes que el registro. Creo que python4 debería eliminar la impresión del lenguaje y forzarlo a usar el registro para eso.
Mnebuerquo
1
Esta es la mejor respuesta !! ... Estaba luchando con la impresión o el sistema o quién sabe ... cuando se necesita un registro adecuado ... gracias por la buena idea
Carlos Saltos
129

Para Python 2, mi elección es: print >> sys.stderr, 'spam' Porque simplemente puede imprimir listas / dictados, etc. print >> sys.stderr, {'spam': 'spam'} en vez de: sys.stderr.write(str({'spam': 'spam'}))

Frankovskyi Bogdan
fuente
66
La forma más pitónica de imprimir un diccionario sería con algo así "{0}".format({'spam': 'spam'}), ¿no? Diría que debe evitar explícitamente la conversión a cadena. Editar: accidentalmente una gramática
luketparkinson
2
@luketparkinson esto se trata de depuración, por lo que creo que es más preferible usar el código más simple posible.
Frankovskyi Bogdan
88
Esto no funciona en Python 3, por lo que debe evitarlo en un nuevo código.
JonnyJD
33

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")
aaguirre
fuente
2
Iba a sugerir que también podría usar un parcial, pero me di cuenta de que parcial asigna el stderr a la función en el momento de la creación del parcial. Esto evita que redirija stderr más tarde, ya que el parcial aún retendrá el objeto stderr original.
Rebs
31

Yo diría que tu primer acercamiento:

print >> sys.stderr, 'spam' 

es el "Uno... forma obvia de hacerlo" Los otros no satisfacen la regla # 1 ("Hermoso es mejor que feo")

Carl F.
fuente
109
Las opiniones difieren. Esto es lo menos obvio para mí.
porgarmingduod
44
@AliVeli No hay paréntesis, esta es una sintaxis anterior de Python <= 2 y, por lo tanto, no es compatible con Python 3.
Rebs
30
Diría que esta es la versión más fea de todos los 3
volcán
44
¿Qué significa eso >>sintácticamente? Entiendo que es un esfuerzo copiar bash >, entonces, ¿es una sintaxis con horquilla para hacer eso?
Dmytro Sirenko
2
@EarlGray Es un remanente del operador de inserción de flujo de C ++:std::cout << "spam";
Sean Allred
19

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')
Brian W.
fuente
8
Agregaría un sys.stderr.flush ()
AMS
55
@AMS - ¿Por qué? printNo incluye un rubor.
Robᵩ
44
¿Por qué imitar cuando realmente puedes hacerlo?
Físico loco
19

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 además sys.stderr.

Florian Castellane
fuente
16

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

Usar parcial solo le ahorra 1 línea de código. La posible confusión 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 en las funciones de ajuste.

from __future__ import print_function
import sys
from functools import partial

error = partial(print, file=sys.stderr)

Luego lo usas así

error('An error occured!')

Puede verificar que se está imprimiendo en stderr y no en stdout haciendo lo siguiente (código superior de 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 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á esta función. Si planea redirigir stderr, utilice el método ** kwargs mencionado por aaguirre en esta página.

Rebs
fuente
¿El código de Corey Goldberg se ejecuta mejor en una máquina Rube Goldberg? : P
Agi Hammerthief
2
Por cierto: "curry" es una palabra clave de búsqueda (más) útil si desea saber más sobre "parcial".
MarcH
5

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 a menudo es 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 sintaxis de print () ha cambiado en Python 3, por lo que si necesita admitir ambas versiones, write () podría ser mejor.

Seppo Enarvi
fuente
44
Usar from __future__ import print_functiones una mejor manera de admitir Python 2.6+ y Python 3.
Phoenix
4

Estoy trabajando en Python 3.4.3. Estoy cortando un poco de mecanografía 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 te da Python se ha convertido en stderr (¿a dónde más iría?), Funciona.

usuario1928764
fuente
2

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!

ThePracticalOne
fuente
Si ejecuto esto, veo una diferencia mucho menor. Es interesante que la mayoría de las respuestas ignoren la forma de la función de impresión (python 3). Nunca lo he usado antes (inercia), pero pensé en ejecutar este script de sincronización y agregar la función de impresión. La comparación directa de la declaración de impresión y la función no es posible (la importación desde el futuro se aplica a todo el archivo y enmascara la declaración de impresión) pero al reescribir este código para usar la función de impresión en lugar de la declaración, veo una mayor velocidad (~ 1.6 aunque algo variable ) a favor de la función de impresión.
hamish
1
El resultado de esta prueba es de alguna manera engañoso. Imprima 'XXXXXXXXXXXXXXXXXXXX' en lugar de 'X' y la proporción cae a 1.05 . Supongo que la mayoría de los programas de Python necesitan imprimir más de un solo carácter.
Siempre preguntando el
15
No me importa el rendimiento, por algo como imprimir advertencias.
wim
Sé que ha pasado un tiempo, pero respondiste igualmente mucho tiempo después de mi publicación ... Si no te interesa el rendimiento, sugeriría que la forma más pitónica sería usar sys.stderr.write y no el WTF?!? ">>" caracteres. Si este espacio de nombres sys.stdout es demasiado largo, puede cambiarle el nombre ... (es decir, desde sys import stderr como stderr_fh). Entonces puedes hacer stderr_fh.write ("bla")
ThePracticalOne
1
[3/3] Incluso si este punto de referencia fuera más preciso, probablemente no valga la pena preocuparse. Como Knuth escribió: "Los programadores pierden enormes cantidades de tiempo pensando o preocupándose por la velocidad de las partes no críticas de sus programas, y estos intentos de eficiencia en realidad tienen un fuerte impacto negativo cuando se consideran la depuración y el mantenimiento. Debemos olvidarnos de los pequeños eficiencias, digamos alrededor del 97% del tiempo: la optimización prematura es la raíz de todo mal ".
Corey Goldberg
1

Si desea salir de un programa debido a un error fatal, use:

sys.exit("Your program caused a fatal error. ... description ...")

y import sysen el encabezado.

feli_x
fuente
-2

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é salida exacta queremos.

La diferencia entre imprimir y la función de escritura de stderr : stderr : stderr (error estándar) es una tubería integrada en todos los sistemas UNIX / Linux, cuando su programa se bloquea e imprime información de depuración (como un rastreo en Python), va al stderr tubo.

impresión : 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 final de Python2 se ha convertido en Python3 en un parámetro, por lo que si usamos comas finales para evitar la nueva línea después de una impresión, en Python3 se verá como print ('Text to print', end = ''), que es un error de sintaxis en Python2 .

http://python3porting.com/noconv.html

Si verificamos lo mismo arriba del escenario en python3:

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

Bajo Python 2.6 hay una importación futura para imprimir en una función. Por lo tanto, para evitar cualquier error de sintaxis y otras diferencias, debemos comenzar cualquier archivo en el que usemos print () con la función de importación futura print_function. 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 separada que funciona tanto en Python2 como en Python3.

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

Caso: Tenga en cuenta que sys.stderr.write () o sys.stdout.write () (stdout (salida estándar) es una tubería 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. Print 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 usando Logging

#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

Vinay Kumar
fuente