Come stampare su stderr in Python?


1340

Esistono diversi modi per scrivere su 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)

Questo sembra contraddire lo zen di Python # 13 , quindi qual è la differenza qui e ci sono vantaggi o svantaggi in un modo o nell'altro? Quale modo dovrebbe essere usato?

Dovrebbe esserci un modo - e preferibilmente solo uno - ovvio per farlo.


46
Il primo modo elencato è una delle tante cose rimosse in Python 3. Il consenso sembra essere che la sintassi >> fosse comunque brutta, e poiché la stampa è ora una funzione, la sintassi non funzionerebbe mai.
Steve Howard,

24
Uso: sys.exit ('Errore: <testo errore>')
rigido

1
usa solo la stampa.
PythonMaster202

Risposte:


1165

Ho scoperto che questo è l'unico corto + flessibile + portatile + leggibile:

from __future__ import print_function
import sys

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

La funzione eprintpuò essere utilizzata allo stesso modo della printfunzione standard :

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz

29
Solo un pensiero: poiché questo importerà la funzione di stampa, ogni altro "stampa" nello script originale dovrà ora essere "funzionalizzato" aggiungendo "(" e ")". Quindi questo è un leggero sciopero contro questo metodo, IMO.
Dan H,

46
@DanH Sì, questo ti costringe a rendere pronto il tuo codice Python3. Immagino che questo potrebbe essere il motivo per cui a molte persone piace davvero!
Marc

18
@MarkH ... sì, ti costringe a rendere pronto il tuo codice Python3 ... ti costringe anche a farlo ADESSO, solo per stampare alcune informazioni di debug sullo stderr ... che troverei più di una seccatura in la maggior parte delle situazioni quando sto cercando di eseguire il debug di qualcosa. (Preferirei non introdurre nuovi errori di sintassi!) :-)
Dan H,

30
FWIW questo codice non ti obbliga a utilizzare la versione della funzione di printtutto il tuo programma. Solo nel modulo contenente la definizione di eprint(). Inseriscilo in un piccolo file da solo, importa eprintda esso negli altri file e puoi continuare a utilizzare l'istruzione printper tutto il tempo che desideri.
alexis,

4
Anche la conversione da funzione di stampa a funzione di stampa è una semplice sostituzione che 2to3 automatizza già per te. Fallo già se non l'hai fatto; python2 sparirà tra meno di 2 anni ... Alcune cose tra 2 e 3 possono diventare un po 'complicate; la funzione di stampa non è una di queste. Vedi docs.python.org/2/library/2to3.html
bobpaul

548
import sys
sys.stderr.write()

È la mia scelta, solo più leggibile e dicendo esattamente cosa intendi fare e portatile tra le versioni.

Modifica: essere 'pythonic' è un terzo pensiero per me sulla leggibilità e le prestazioni ... con queste due cose in mente, con python l'80% del tuo codice sarà pythonic. la comprensione dell'elenco è la "grande cosa" che non viene utilizzata spesso (leggibilità).


88
Basta non dimenticare di sciacquare.
temoto,

10
Il vantaggio printdell'istruzione è la stampa semplice di valori non stringa, senza prima convertirli. Se hai bisogno di una dichiarazione di stampa, ti consiglio quindi di utilizzare la terza opzione per essere pronto per Python 3
vdboor,

56
sys.stderr.write()non è niente di simile print. Non aggiunge una nuova riga.
Colonnello Panic,

41
@temoto - stderr non è bufferizzato, quindi non è necessario scaricare.
Matt

11
@SkipHuffman Intendi os.linesep. Di questo stderrstiamo parlando, dopo tutto. Non voglio che la console si rovini con la newline sbagliata.
jpmc26,

182

print >> sys.stderrè andato in 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)

Per molti di noi, sembra in qualche modo innaturale relegare la destinazione alla fine del comando. L'alternativa

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

sembra più orientato agli oggetti e va elegantemente dal generico allo specifico. Ma nota che writenon è un sostituto 1: 1 per print.


6
Suppongo che sia una questione di preferenza, ma non vedo cosa sia brutto print('spam', file=sys.stderr). Se lo fai più e più volte, puoi codificare la funzione 'eprint' come nella risposta più popolare, ma in tal caso, vorrei chiedere, cosa c'è di sbagliato con la registrazione? stackoverflow.com/a/41304513/1450294
Michael Scheper il

1
Un altro modo per chiarire l'intento sarebbe quello di fare with sys.stderr as dest:prima di una chiamata rientrata aprint("ERROR", file=dest)
MarkHu,

131

Nessuno è loggingancora stato menzionato , ma la registrazione è stata creata appositamente per comunicare messaggi di errore. La configurazione di base imposterà un gestore di flusso che scrive su stderr.

Questo script:

# foo.py
import logging

logging.basicConfig(format='%(message)s')
log = logging.getLogger(__name__)
log.warning('I print to stderr by default')
print('hello world')

ha il seguente risultato quando eseguito sulla riga di comando:

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

e bar.txt conterrà il 'ciao mondo' stampato su stdout.


3
Nella mia esperienza, più persone usano print per registrare i messaggi che usare la registrazione. Penso che python4 dovrebbe semplicemente rimuovere la stampa dal linguaggio e costringerti a usare la registrazione per quello.
Mnebuerquo,

1
Questa è la risposta migliore !! ... Stavo lottando con la stampa o il sistema o chissà ... quando è necessaria una registrazione adeguata ... grazie per la buona idea
Carlos Saltos,

129

Per Python 2 la mia scelta è: print >> sys.stderr, 'spam' perché puoi semplicemente stampare liste / dicts ecc. Senza convertirlo in stringa. print >> sys.stderr, {'spam': 'spam'} invece di: sys.stderr.write(str({'spam': 'spam'}))


6
Il modo più Pythonic di stampare un dizionario sarebbe con qualcosa come "{0}".format({'spam': 'spam'})comunque, no? Direi che dovresti evitare di convertirti esplicitamente in stringa. Modifica: ho accidentalmente una grammatica
luketparkinson il

2
@luketparkinson tutto questo sul debug - quindi, penso, è più preferibile usare il codice più semplice possibile.
Frankovskyi Bogdan,

88
Questo non funziona su Python 3, quindi dovresti evitarlo con un nuovo codice.
JonnyJD,

33

Ho fatto quanto segue usando Python 3:

from sys import stderr

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

Quindi ora sono in grado di aggiungere argomenti di parole chiave, ad esempio, per evitare il ritorno a capo:

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

2
Stavo per suggerire che potresti usare anche un parziale, ma mi sono reso conto che il parziale assegna lo stderr alla funzione al momento della creazione del parziale. Ciò impedisce di reindirizzare stderr in un secondo momento poiché il parziale conterrà comunque l'oggetto stderr originale.
Rebs il

31

Direi che il tuo primo approccio:

print >> sys.stderr, 'spam' 

è il "Uno ... ovvio modo di farlo" Gli altri non soddisfano la regola n. 1 ("Bello è meglio del brutto").


109
Le opinioni sono diverse. Questo è il meno ovvio per me.
porgarmingduod,

4
@AliVeli Non ci sono parentesi, questa è una vecchia sintassi Python <= 2 e quindi non compatibile con Python 3.
Rebs il

30
Direi che questa è la versione più brutta di tutti e 3
vulcano il

4
Cosa >>significa sintatticamente? Capisco che è uno sforzo per copiare i bash >, quindi è una sintassi calpestata fare proprio questo?
Dmytro Sirenko,

2
@EarlGray È un holdover dall'operatore di inserimento stream di C ++:std::cout << "spam";
Sean Allred,

19

Questo imiterà la funzione di stampa standard ma emetterà su stderr

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

8
Vorrei aggiungere un sys.stderr.flush ()
AMS

5
@AMS - Perché? printnon include un flush.
Robᵩ

4
Perché imitare quando puoi effettivamente farlo?
Fisico pazzo,

19

In Python 3, si può semplicemente usare print ():

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

quasi fuori dalla scatola:

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

o:

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

Questo è semplice e non ha bisogno di includere altro sys.stderr.


16

MODIFICA Con il senno di poi, penso che la potenziale confusione con il cambiamento di sys.stderr e il non vedere il comportamento aggiornato rende questa risposta non buona come usare semplicemente una funzione come altri hanno sottolineato.

L'uso parziale consente di salvare solo 1 riga di codice. La potenziale confusione non vale la pena salvare 1 riga di codice.

originale

Per renderlo ancora più semplice, ecco una versione che usa 'parziale', che è di grande aiuto nelle funzioni di wrapping.

from __future__ import print_function
import sys
from functools import partial

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

Quindi lo usi in questo modo

error('An error occured!')

Puoi verificare che stia stampando su stderr e non stdout procedendo come segue (codice di over-riding da 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!")

Il rovescio della medaglia a questo è parziale assegna il valore di sys.stderr alla funzione wrapped al momento della creazione. Che significa, se reindirizzi stderr in seguito non influirà su questa funzione. Se hai intenzione di reindirizzare stderr, usa il metodo ** kwargs menzionato da aaguirre in questa pagina.


Il codice Corey Goldberg può essere eseguito al meglio su una macchina Rube Goldberg? : P
Agi Hammerthief,

2
A proposito: "curry" è una (più) parola chiave di ricerca utile se vuoi saperne di più su "parziale".
MarcH,

5

Lo stesso vale per stdout:

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

Come indicato nelle altre risposte, print offre un'interfaccia carina che è spesso più conveniente (ad esempio per stampare informazioni di debug), mentre la scrittura è più veloce e può anche essere più conveniente quando si deve formattare l'output esattamente in un certo modo. Considererei anche la manutenibilità:

  1. In seguito puoi decidere di passare da stdout / stderr a un file normale.

  2. La sintassi di print () è cambiata in Python 3, quindi se è necessario supportare entrambe le versioni, write () potrebbe essere migliore.


4
Usare from __future__ import print_functionè un modo migliore per supportare sia Python 2.6+ sia Python 3.
phoenix

4

Sto lavorando in Python 3.4.3. Sto tagliando un po 'di battitura che mostra come sono arrivato qui:

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

Ha funzionato? Prova a reindirizzare stderr su un file e guarda cosa succede:

[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]$

Bene, a parte il fatto che la piccola introduzione che ti dà Python è stata trasformata in stderr (dove altro andrebbe?), Funziona.


2

Se fai un semplice test:

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))

Scoprirai che sys.stderr.write () è costantemente 1.81 volte più veloce!


Se lo eseguo vedo una differenza molto più piccola. È interessante notare che la maggior parte delle risposte ignora la funzione di stampa (python 3). Non l'ho mai usato prima (inerzia), ma ho pensato di eseguire questo script di temporizzazione e aggiungere la funzione di stampa. Il confronto diretto dell'istruzione e della funzione di stampa non è possibile (l'importazione dal futuro si applica all'intero file e maschera l'istruzione di stampa) ma riscrivendo questo codice per utilizzare la funzione di stampa anziché l'istruzione, vedo una maggiore velocità (~ 1.6 sebbene un po 'variabile ) a favore della funzione di stampa.
hamish

1
Il risultato di questo test è in qualche modo fuorviante. Stampa 'XXXXXXXXXXXXXXXXXXXX' invece di 'X' e il rapporto scende a 1,05 . Suppongo che la maggior parte dei programmi Python debba stampare più di un singolo personaggio.
Chiedere sempre il

15
Non mi importa delle prestazioni, per qualcosa come stampare gli avvisi.
Wim

So che è passato un po 'di tempo, ma hai risposto ugualmente molto tempo dopo il mio post ... Se non ti preoccupi delle prestazioni di quanto suggerirei, il modo più pitonico sarebbe usare sys.stderr.write e non il WTF?!? caratteri ">>". Se questo spazio dei nomi sys.stdout è troppo lungo, puoi rinominarlo ... (ad es. Da sys import stderr come stderr_fh). Quindi puoi fare stderr_fh.write ("blah")
ThePracticalOne

1
[3/3] Anche se questo benchmark fosse più preciso, probabilmente non vale la pena preoccuparsi. Come ha scritto Knuth: "I programmatori sprecano enormi quantità di tempo pensando o preoccupandosi della velocità delle parti non critiche dei loro programmi e questi tentativi di efficienza hanno effettivamente un forte impatto negativo quando si considerano il debug e la manutenzione. efficienze, dicono circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali. "
Corey Goldberg,

1

Se si desidera uscire da un programma a causa di un errore irreversibile, utilizzare:

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

e import sysnell'intestazione.


-2

La risposta alla domanda è: Esistono diversi modi per stampare stderr in Python ma ciò dipende da 1.) quale versione di Python stiamo usando 2.) quale output esatto vogliamo.

La differenza tra print e la funzione di scrittura di stderr : stderr : stderr (errore standard) è una pipe integrata in ogni sistema UNIX / Linux, quando il programma si arresta in modo anomalo e stampa informazioni di debug (come un traceback in Python), va allo stderr tubo.

Stampa : print è un wrapper che formatta gli input (l'input è lo spazio tra argomento e la nuova riga alla fine) e quindi chiama la funzione di scrittura di un determinato oggetto, l'oggetto dato di default è sys.stdout, ma possiamo passare un file, cioè possiamo anche stampare l'input in un file.

Python2: Se stiamo usando python2, allora

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

La virgola finale di Python2 è diventata un parametro in Python3, quindi se usiamo le virgole finali per evitare la nuova riga dopo una stampa, in Python3 sembrerà print ('Text to print', end = '') che è un errore di sintassi in Python2 .

http://python3porting.com/noconv.html

Se controlliamo lo stesso sopra sceario in python3:

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

In Python 2.6 c'è un'importazione futura per rendere la stampa in una funzione. Quindi, per evitare errori di sintassi e altre differenze, dovremmo iniziare qualsiasi file in cui utilizziamo print () dalla futura import print_function. L' importazione futura funziona solo con Python 2.6 e versioni successive, quindi per Python 2.5 e versioni precedenti hai due opzioni. Puoi convertire la stampa più complessa in qualcosa di più semplice oppure puoi utilizzare una funzione di stampa separata che funziona sia con Python2 che con Python3.

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

Caso: si noti che sys.stderr.write () o sys.stdout.write () (stdout (output standard) è una pipe integrata in ogni sistema UNIX / Linux) non è un sostituto per la stampa, ma sì possiamo usarlo come alternativa in alcuni casi. Stampa è un wrapper che avvolge l'input con spazio e newline alla fine e utilizza la funzione di scrittura per scrivere. Questo è il motivo per cui sys.stderr.write () è più veloce.

Nota: possiamo anche tracciare ed eseguire il debug utilizzando la registrazione

#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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.