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.


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

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


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.


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.


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


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

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


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

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.


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.


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.


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.


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!


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.


-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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.