Como imprimir em stderr em Python?

Eu me deparei com várias maneiras de escrever para stderr:

# Note: this first one is longer working 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) 

Parece contradizer o zen do Python # 13 , então qual é a maneira preferida de fazer isso? Existem vantagens ou desvantagens de uma forma ou de outra?

Deve haver uma – e de preferência apenas uma – maneira óbvia de fazê-lo.

Eu encontrei este para ser o único curto + flexível + portátil + legível:

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

A function eprint pode ser usada da mesma forma que a function de print padrão:

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

sys.stderr.write() é a minha escolha, apenas mais legível e dizendo exatamente o que você pretende fazer e portátil em todas as versões.

Edit: ser ‘pythonic’ é um terceiro pensamento para mim sobre legibilidade e performance … com estas duas coisas em mente, com python 80% do seu código será pythonic. compreensão da lista é a “grande coisa” que não é usada com tanta frequência (legibilidade).

Para o Python 2, minha escolha é: print >> sys.stderr, 'spam' Porque você pode simplesmente imprimir listas / dictionarys etc. sem convertê-lo em string. print >> sys.stderr, {'spam': 'spam'} vez de: sys.stderr.write(str({'spam': 'spam'}))

print >> sys.stderr se foi em Python3. http://docs.python.org/3.0/whatsnew/3.0.html diz:

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

Infelizmente, isso é muito feio. Como alternativa, use

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

mas note que write não é uma substituição 1: 1 para print .

Ninguém mencionou o logging ainda, mas o registro foi criado especificamente para comunicar mensagens de erro. Por padrão, ele está configurado para gravar em stderr. Este script:

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

tem o seguinte resultado quando executado na linha de comando:

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

(e bar.txt contém o ‘olá mundo’)

Eu diria que sua primeira abordagem:

 print >> sys.stderr, 'spam' 

é o “Um … jeito óbvio de fazê-lo” Os outros não satisfazem a regra # 1 (“Linda é melhor que feia”).

Eu fiz o seguinte usando o Python 3:

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

Então agora eu posso adicionar argumentos de palavras-chave, por exemplo, para evitar o retorno de carro:

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

Isso imitará a function de impressão padrão, mas a saída no stderr

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

EDIT Na visão de trás, eu acho que a confusão potencial com a mudança de sys.stderr e não ver o comportamento atualizado faz com que essa resposta não seja tão boa quanto apenas usar uma function simples como outros apontaram.

Usando parcial só você economiza 1 linha de código. A confusão potencial não vale a pena salvar uma linha de código.

original

Para facilitar ainda mais, aqui está uma versão que usa ‘parcial’, o que é uma grande ajuda nas funções de empacotamento.

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

Você então usá-lo assim

 error('An error occured!') 

Você pode verificar se está imprimindo para stderr e não stdout fazendo o seguinte (código de acompanhamento 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!") 

A desvantagem disso é parcial atribui o valor de sys.stderr à function envolvida no momento da criação. O que significa que, se você redirect o stderr mais tarde, isso não afetará essa function. Se você planeja redirect o stderr, então use o método ** kwargs mencionado por aaguirre nesta página.

O mesmo se aplica ao stdout:

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

Como afirmado nas outras respostas, a impressão oferece uma interface bonita que é geralmente mais conveniente (por exemplo, para imprimir informações de debugging), enquanto a gravação é mais rápida e também pode ser mais conveniente quando você precisa formatar a saída exatamente de uma determinada maneira. Eu consideraria a manutenção também:

  1. Posteriormente, você pode decidir alternar entre stdout / stderr e um arquivo regular.

  2. A syntax print () mudou no Python 3, então se você precisar suportar ambas as versões, write () pode ser melhor.

Eu estou trabalhando em python 3.4.3. Estou cortando um pouco de digitação que mostra como cheguei aqui:

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

Funcionou? Tente redirect o stderr para um arquivo e veja o que acontece:

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

Bem, além do fato de que a pequena introdução que python oferece a você foi sugada para stderr (onde mais ela iria?), Funciona.

Se você fizer um teste simples:

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

Você vai descobrir que sys.stderr.write () é consistentemente 1,81 vezes mais rápido!

Experimentar:

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

A resposta para a pergunta é: Há uma maneira diferente de imprimir stderr em python, mas isso depende de 1.) qual versão em python estamos usando 2.) qual saída exata queremos.

A diferença entre a function de gravação de print e stderr: stderr : stderr (erro padrão) é um pipe embutido em cada sistema UNIX / Linux, quando seu programa trava e imprime informações de debugging (como um traceback em Python), ele vai para o stderr tubo.

print : print é um wrapper que formata as inputs (a input é o espaço entre o argumento e a nova linha no final) e então chama a function write de um dado object, o object dado por padrão é sys.stdout, mas podemos passar um arquivo ou seja, podemos imprimir a input em um arquivo também.

Python2: Se estamos usando python2, então

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

A vírgula final do Python2 em Python3 se tornou um parâmetro, portanto, se usarmos vírgulas à direita para evitar a nova linha depois de uma impressão, isso parecerá com impressão (‘Texto para impressão’, fim = ‘) que é um erro de syntax sob Python2 .

http://python3porting.com/noconv.html

Se nós verificamos o mesmo acima do sceario em python3:

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

No Python 2.6, há uma importação futura para tornar a impressão em uma function. Portanto, para evitar erros de syntax e outras diferenças, devemos iniciar qualquer arquivo em que usarmos print () com a partir do futuro import_impress_function. A importação futura funciona somente no Python 2.6 e posterior, portanto, para o Python 2.5 e versões anteriores, você tem duas opções. Você pode converter a impressão mais complexa em algo mais simples ou usar uma function de impressão separada que funcione sob o Python2 e o Python3.

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

Caso: Apontar para o fato de que sys.stderr.write () ou sys.stdout.write () (stdout (saída padrão) é um canal embutido em todo sistema UNIX / Linux) não é um substituto para impressão, mas sim Podemos usá-lo como uma alternativa em alguns casos. Print é um wrapper que envolve a input com espaço e nova linha no final e usa a function write para gravar. Essa é a razão pela qual sys.stderr.write () é mais rápido.

Nota: também podemos rastrear e 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

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

log de pydoc