python-2.7 - Como imprimir em stderr em Python?





printing zen (13)


EDIT Na visão de trás, 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 função 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 (exagerando no código 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 envolvida no momento da criação. O que significa que, se você redirecionar o stderr mais tarde, isso não afetará essa função. Se você planeja redirecionar o stderr, então use o método ** kwargs mencionado por aaguirre nesta página.

Eu me deparei com várias maneiras de escrever para 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)

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.




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 .




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




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 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 determinada maneira. Eu consideraria a manutenção também:

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

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




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: sendo '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).




Experimentar:

from sys import stderr


print >> sys.stderr, 'spam' 



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.warning('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')

(Nota, logging.warn foi deprecated , use logging.warning )




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



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!




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

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

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

[18:22 [email protected]-LT7 pexpect]$ python3 2> /tmp/test.txt
>>> import sys
>>> print("testing", file=sys.stderr)
>>> [18:22 [email protected]-LT7 pexpect]$
[18:22 [email protected]-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 [email protected]-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.




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 função de gravação de print e stderr: stderr : stderr (erro padrão) é um pipe embutido em todo sistema 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 wrapper que formata as entradas (a entrada é o espaço entre o argumento e a nova linha no final) e então chama a função write de um determinado objeto, o objeto dado por padrão é sys.stdout, mas podemos passar um arquivo ou seja, podemos imprimir a entrada 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, em Python3 será como imprimir ('Texto para imprimir', fim = ') que é um erro de sintaxe em 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 função. Portanto, para evitar erros de sintaxe e outras diferenças, devemos iniciar qualquer arquivo em que usarmos print () com a partir da futura print_function de importação. 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 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: Apontar para o fato de que sys.stderr.write () ou sys.stdout.write () (stdout (saída padrão) é um canal embutido em cada 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 entrada com espaço e nova linha no final e usa a função 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




typeé na verdade uma metaclass- uma classe que cria outras classes. A maioria metaclasssão subclasses de type. O metaclassrecebe a newclasse como seu primeiro argumento e fornece acesso ao objeto de classe com detalhes conforme mencionado abaixo:

>>> class MetaClass(type):
...     def __init__(cls, name, bases, attrs):
...         print ('class name: %s' %name )
...         print ('Defining class %s' %cls)
...         print('Bases %s: ' %bases)
...         print('Attributes')
...         for (name, value) in attrs.items():
...             print ('%s :%r' %(name, value))
... 

>>> class NewClass(object, metaclass=MetaClass):
...    get_choch='dairy'
... 
class name: NewClass
Bases <class 'object'>: 
Defining class <class 'NewClass'>
get_choch :'dairy'
__module__ :'builtins'
__qualname__ :'NewClass'

Note:

Observe que a classe não foi instanciada a qualquer momento; o simples ato de criar a classe desencadeou a execução do metaclass.





python python-2.7 printing stderr zen