Como imprimir em stderr em Python?

1340

Existem várias maneiras de escrever no 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)

Isso parece contradizer o zen do Python # 13 , então qual é a diferença aqui e existem vantagens ou desvantagens de uma maneira ou de outra? Qual caminho deve ser usado?

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

wim
fonte
46
A primeira maneira listada é uma das muitas coisas removidas no Python 3. O consenso parece ser que a sintaxe >> era feia de qualquer maneira e, como a impressão agora é uma função, a sintaxe nunca funcionaria.
Steve Howard
24
Eu uso: sys.exit ( 'Erro: <error text>')
gritante
1
basta usar print.
PythonMaster202

Respostas:

1165

Eu achei que este era o único pequeno + flexível + portátil + legível:

from __future__ import print_function
import sys

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

A função eprintpode ser usada da mesma maneira que a printfunção padrão :

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
Marcha
fonte
29
Apenas um pensamento: como isso importará a função de impressão, todas as outras "impressões" no script original agora precisarão ser "funcionalizadas" adicionando "(" e ")". Portanto, esse é um pequeno ataque contra esse método, IMO.
11558 Dan H
46
@ DanH Sim, isso força você a tornar seu código pronto para Python3. Eu acho que pode ser por isso que muitas pessoas realmente gostam!
MarcH 18/11/19
18
@ MarkH ... sim, obriga você a tornar seu código pronto para Python3 ... também obriga a fazê-lo AGORA, apenas para imprimir algumas informações de depuração no stderr ... o que eu consideraria mais problemático no Na maioria das situações, quando estou tentando depurar alguma coisa. (Eu prefiro não introduzir novos erros de sintaxe!) :-)
Dan H
30
FWIW esse código não força você a usar a versão da função printem todo o seu programa. Somente no módulo que contém a definição de eprint(). Coloque-o em um pequeno arquivo, importe eprint-o para seus outros arquivos e você poderá continuar usando a instrução printpelo tempo que desejar.
Alexis
4
Além disso, a conversão da função de impressão para impressão é uma simples substituição que o 2to3 já automatiza para você. Apenas faça isso se você não tiver; python2 desaparecerá em menos de 2 anos ... Algumas coisas entre 2 e 3 podem ficar um pouco complicadas; A função de impressão não é uma delas. Veja docs.python.org/2/library/2to3.html
bobpaul
548
import sys
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 desempenho ... com essas duas coisas em mente, com python 80% do seu código será python. a compreensão da lista é a "grande coisa" que não é usada com tanta frequência (legibilidade).

Mike Ramirez
fonte
88
Só não se esqueça de dar descarga.
temoto 03/04
10
A vantagem da printdeclaração é a impressão fácil de valores que não são de cadeia, sem a necessidade de convertê-los primeiro. Se precisar de uma declaração de impressão, eu recomendo, portanto, usando a terceira opção a ser python 3 pronto
vdboor
56
sys.stderr.write()não é nada assim print. Não adiciona uma nova linha.
Coronel Panic
41
@temoto - stderr não é armazenado em buffer, então não há necessidade de liberar.
Matt
11
@SkipHuffman Você quer dizer os.linesep. Isso é stderrque estamos falando, afinal. Não quero que o console mexa com a nova linha errada.
jpmc26
182

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

Para muitos de nós, parece um pouco natural relegar o destino ao final do comando. A alternativa

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

parece mais orientado a objetos e elegantemente vai do genérico ao específico. Mas observe que writenão é um substituto 1: 1 para print.

Joachim W
fonte
6
Suponho que seja uma questão de preferência, mas não vejo o que é feio print('spam', file=sys.stderr). Se você estiver repetindo várias vezes, poderá codificar a função 'eprint' como na resposta mais popular, mas, nesse caso, eu perguntaria: o que há de errado com o log? stackoverflow.com/a/41304513/1450294
Michael Scheper
1
Outra maneira de esclarecer a intenção seria fazer with sys.stderr as dest:antes uma chamada recuado paraprint("ERROR", file=dest)
MarkHu
131

Ninguém mencionou loggingainda, mas o log foi criado especificamente para comunicar mensagens de erro. A configuração básica configurará um manipulador de fluxo gravando no stderr.

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

tem o seguinte resultado quando executado na linha de comando:

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

e bar.txt conterá o 'hello world' impresso no stdout.

lamacento
fonte
3
Na minha experiência, mais pessoas usam a impressão para registrar mensagens do que o registro. Eu acho que o python4 deve apenas remover a impressão da linguagem e forçá-lo a usar o log para isso.
Mnebuerquo 28/03
1
Esta é a melhor resposta !! ... Eu estava lutando com impressão ou sys ou quem sabe ... quando uma madeireira adequada é necessário ... obrigado pela boa idéia
Carlos Saltos
129

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

Frankovskyi Bogdan
fonte
6
A maneira mais pitônica de imprimir um dicionário seria com algo "{0}".format({'spam': 'spam'})assim, não é? Eu diria que você deve evitar a conversão explícita em string. Edit: Eu acidentalmente uma gramática
luketparkinson
2
@luketparkinson tudo isso sobre depuração - então, eu acho, é mais preferível usar o código mais simples possível.
Frankovskyi Bogdan
88
Isso não funciona no Python 3, portanto você deve evitá-lo no novo código.
JonnyJD
33

Eu fiz o seguinte usando Python 3:

from sys import stderr

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

Portanto, 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")
aaguirre
fonte
2
Eu sugeriria que você também pudesse usar uma parcial, mas percebi que parcial atribui o stderr à função no momento da criação da parcial. Isso impede que você redirecione o stderr posteriormente, pois o parcial ainda manterá o objeto stderr original.
Rebs
31

Eu diria que sua primeira abordagem:

print >> sys.stderr, 'spam' 

é a "Uma... maneira óbvia de fazê-lo". Os outros não cumprem a regra 1 ("Bonito é melhor que feio").

Carl F.
fonte
109
As opiniões são diferentes. Isso é o menos óbvio para mim.
Porgarmingduod
4
@AliVeli Não há parênteses, essa é uma sintaxe antiga do Python <= 2 e, portanto, não é compatível com o Python 3.
quer
30
Eu diria que esta é a versão mais feia de todos os 3
vulcão
4
O que isso >>significa sintaticamente? Eu entendo que é um esforço copiar cópias do bash >, então é alguma sintaxe do calçado para fazer exatamente isso?
Dmytro Sirenko
2
@EarlGray É uma reserva do operador de inserção de fluxo do C ++:std::cout << "spam";
Sean Allred
19

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

def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '\n')
Brian W.
fonte
8
Gostaria de adicionar um sys.stderr.flush ()
AMS
5
@AMS - Por quê? printnão inclui um flush.
Robᵩ
4
Por que imitar quando você pode realmente fazê-lo?
Mad Físico
19

No Python 3, pode-se usar apenas print ():

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

quase fora da caixa:

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

ou:

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

Isso é direto e não precisa incluir nada além disso sys.stderr.

Florian Castellane
fonte
16

EDIT Em retrospectiva, acho que a potencial confusão com a mudança do sys.stderr e a falta de atualização do comportamento fazem com que essa resposta não seja tão boa quanto usar apenas uma função simples, como outros já apontaram.

Usar parcial apenas poupa 1 linha de código. A confusão em potencial não vale a pena salvar 1 linha de código.

original

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

from __future__ import print_function
import sys
from functools import partial

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

Você então usa assim

error('An error occured!')

Você pode verificar se está imprimindo no stderr e não no stdout fazendo o seguinte (código de substituição 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 à função agrupada no momento da criação. O que significa que, se você redirecionar o stderr posteriormente, isso não afetará esta função. Se você planeja redirecionar o stderr, use o método ** kwargs mencionado por aaguirre nesta página.

Rebs
fonte
O código de Corey Goldberg é melhor executado em uma máquina Rube Goldberg? : P
Agi Hammerthief
2
BTW: "currying" é uma (mais) palavra-chave de pesquisa útil se você quiser saber mais sobre "parcial".
Março
5

O mesmo se aplica ao stdout:

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

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

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

  2. A sintaxe print () mudou no Python 3, portanto, se você precisar suportar as duas versões, write () poderá ser melhor.

Seppo Enarvi
fonte
4
Usando from __future__ import print_functioné a melhor maneira de apoiar tanto Python 2.6+ e Python 3.
Phoenix
4

Estou trabalhando no 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 redirecionar 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 o python oferece a você foi arrastada para o stderr (para onde mais ele iria?), Funciona.

user1928764
fonte
2

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ê verá que sys.stderr.write () é consistentemente 1,81 vezes mais rápido!

ThePracticalOne
fonte
Se eu executar isso, vejo uma diferença muito menor. É interessante que a maioria das respostas ignore a maneira da função de impressão (python 3). Eu nunca o usei antes (inércia), mas pensei em executar esse script de temporização e adicionar a função de impressão. A comparação direta da instrução e função de impressão não é possível (a importação do futuro se aplica a todo o arquivo e oculta a instrução de impressão), mas, reescrevendo esse código para usar a função de impressão em vez da instrução, vejo uma velocidade maior (~ 1,6, embora um tanto variável ) a favor da função de impressão.
hamish
1
O resultado desse teste é de alguma forma enganoso. Imprima 'XXXXXXXXXXXXXXXXXXXX' em vez de 'X' e a proporção cai para 1,05 . Presumo que a maioria dos programas em python precise imprimir mais de um único caractere.
Sempre perguntando
15
Não me importo com desempenho, para algo como imprimir avisos.
Wim
Eu sei que já faz um tempo, mas você respondeu igualmente por muito tempo depois do meu post ... Se você não se importa com o desempenho, eu sugeriria que a maneira mais pitônica seria usar sys.stderr.write e não o WTF?!? caracteres ">>". Se esse espaço para nome sys.stdout for muito longo, você poderá renomeá-lo ... (ou seja, de sys import stderr como stderr_fh). Então você pode fazer stderr_fh.write ( "blah")
ThePracticalOne
1
[3/3] Mesmo que esse benchmark seja mais preciso, provavelmente não vale a pena se preocupar. Como escreveu Knuth: "Os programadores perdem muito tempo pensando ou se preocupando com a velocidade das partes não críticas de seus programas, e essas tentativas de eficiência realmente têm um forte impacto negativo quando a depuração e a manutenção são consideradas. Devemos esquecer as pequenas eficiências, digamos, cerca de 97% das vezes: a otimização prematura é a raiz de todo mal. "
Corey Goldberg #
1

Se você deseja sair de um programa devido a um erro fatal, use:

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

e import sysno cabeçalho.

feli_x
fonte
-2

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

A diferença entre a função de gravação print e stderr: stderr : stderr (erro padrão) é um pipe que é incorporado em todos os sistemas UNIX / Linux, quando seu programa trava e imprime informações de depuração (como um traceback em Python), ele vai para o stderr tubo.

print : print é um invólucro que formata as entradas (a entrada é o espaço entre o argumento e a nova linha no final) e, em seguida, chama a função de gravação de um determinado objeto, o objeto fornecido por padrão é sys.stdout, mas podemos passar um arquivo, ou seja, também podemos imprimir a entrada em um arquivo.

Python2: Se estamos usando python2, então

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

A vírgula à direita do Python2 no Python3 se tornou um parâmetro; portanto, se usarmos vírgulas à direita para evitar a nova linha após uma impressão, no Python3 será semelhante à impressão ('Text to print', end = ''), que é um erro de sintaxe no Python2. .

http://python3porting.com/noconv.html

Se verificarmos o mesmo sceario acima em python3:

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

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

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

Caso: Observe que sys.stderr.write () ou sys.stdout.write () (stdout (saída padrão) é um canal incorporado a todos os sistemas UNIX / Linux) não substitui a impressão, mas sim podemos usá-lo como uma alternativa em alguns casos. Imprimir é um invólucro que agrupa a entrada com espaço e nova linha no final e usa a função de gravação para escrever. Esta é a razão pela qual sys.stderr.write () é mais rápido.

Nota: também podemos rastrear e depurar usando o Log

#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
fonte