web-dev-qa-db-fra.com

Comment imprimer sur stderr en Python?

Il y a plusieurs façons d'écrire sur 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)

Cela semble contredire zen de Python # 1 Alors, quelle est la différence ici et y at-il des avantages ou des inconvénients à l’une ou l’autre voie? Quel chemin devrait être utilisé?

Il devrait y avoir un - et de préférence un seul - moyen évident de le faire.

1148
wim

J'ai trouvé que c'était le seul court + flexible + portable + lisible:

from __future__ import print_function
import sys

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

La fonction eprintpeut être utilisée de la même manière que la fonction standard printname__:

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
985
MarcH
import sys
sys.stderr.write()

Est-ce mon choix, juste plus lisible et dire exactement ce que vous avez l’intention de faire et portable à travers les versions.

Éditer: être 'Pythonic' est une troisième pensée pour moi en ce qui concerne la lisibilité et les performances ... avec ces deux choses à l’esprit, avec Python, 80% de votre code sera en Pythonic. la compréhension de liste est la "grande chose" qui n'est pas utilisée aussi souvent (lisibilité).

482
Mike Ramirez

Pour Python 2, mon choix est: print >> sys.stderr, 'spam' Parce que vous pouvez simplement imprimer des listes/plans, etc. sans le convertir en chaîne. print >> sys.stderr, {'spam': 'spam'} au lieu de: sys.stderr.write(str({'spam': 'spam'}))

131

print >> sys.stderr est parti en Python3. http://docs.python.org/3.0/whatsnew/3.0.html dit:

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

Pour bon nombre d'entre nous, il semble quelque peu anormal de reléguer la destination à la fin de la commande. L'alternative

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

semble plus orienté objet, et va élégamment du générique au spécifique. Cependant, notez que write n'est pas un remplacement 1: 1 de print.

116
Joachim W

Personne n'a encore mentionné logging, mais la journalisation a été créée spécifiquement pour communiquer des messages d'erreur. Par défaut, il est configuré pour écrire sur stderr. Ce 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')

a le résultat suivant lorsqu'il est exécuté sur la ligne de commande:

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

(et bar.txt contient le 'bonjour le monde')

(Remarque: logging.warn a été obsolète , utilisez logging.warning à la place)

94
slushy

Je dirais que votre première approche:

print >> sys.stderr, 'spam' 

est le "One.. --- évident façon de le faire" Les autres ne satisfont pas la règle n ° 1 ("Beau vaut mieux que moche.")

32
Carl F.

J'ai fait ce qui suit en utilisant Python 3:

from sys import stderr

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

Alors maintenant, je peux ajouter des arguments de mots-clés, par exemple, pour éviter les retours chariot:

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

Ceci imitera la fonction d’impression standard mais sera imprimé sur stderr

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

EDIT En rétrospective, je pense que la confusion possible avec le changement de sys.stderr et le fait de ne pas voir le comportement mis à jour rendent cette réponse moins bonne que juste en utilisant une fonction simple comme d'autres l'ont souligné.

L'utilisation partielle ne vous permet d'économiser qu'une ligne de code. La confusion potentielle ne vaut pas la peine d’enregistrer une ligne de code.

original

Pour rendre cela encore plus facile, voici une version qui utilise "partiel", ce qui est une aide précieuse pour le wrapping de fonctions.

from __future__ import print_function
import sys
from functools import partial

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

Vous l'utilisez alors comme si

error('An error occured!')

Vous pouvez vérifier que l'impression s'effectue sur stderr et non sur stdout en procédant comme suit (code de sur-circonscription 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!")

L'inconvénient de ceci est partiel affecte la valeur de sys.stderr à la fonction encapsulée au moment de la création. Ce qui signifie que si vous redirigez stderr plus tard, cela n’affectera pas cette fonction. Si vous envisagez de rediriger stderr, utilisez la méthode ** kwargs mentionnée par aaguirre sur cette page.

17
Rebs

Dans Python 3, on peut simplement utiliser print ():

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

presque sorti de la boîte:

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

ou:

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

C'est simple et il n'est pas nécessaire d'inclure autre chose que sys.stderr.

9
Florian Castellane

La même chose s'applique à stdout:

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

Comme indiqué dans les autres réponses, print offre une jolie interface qui est souvent plus pratique (par exemple, pour imprimer des informations de débogage), tandis que write est plus rapide et peut également être plus pratique lorsque vous devez formater la sortie exactement d'une certaine manière. Je considérerais également la maintenabilité:

  1. Vous pourrez ultérieurement décider de basculer entre stdout/stderr et un fichier normal.

  2. print () la syntaxe a été modifiée dans Python 3, donc si vous devez prendre en charge les deux versions, write () peut être préférable.

7
Seppo Enarvi

Je travaille dans python 3.4.3. Je coupe un peu de frappe qui montre comment je suis arrivé ici:

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

Cela a-t-il fonctionné? Essayez de rediriger stderr vers un fichier et voyez ce qui se passe:

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

Eh bien, mis à part le fait que la petite introduction que python vous a été insérée dans stderr (où irait-il sinon?), Cela fonctionne.

6
user1928764

Si vous faites un test simple:

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

Vous constaterez que sys.stderr.write () est toujours 1.81 fois plus rapide!

3
ThePracticalOne

La réponse à la question est la suivante: il existe différentes manières d’imprimer stderr dans python, mais cela dépend de 1.) quelle version python que nous utilisons 2.) quelle sortie exacte nous voulons.

La différence entre print et la fonction d'écriture de stderr: stderr : stderr (erreur standard) est un tuyau intégré à chaque système UNIX/Linux, lorsque votre programme se bloque. et affiche les informations de débogage (comme une trace en Python), il passe dans le canal stderr.

print : print est un wrapper qui formate les entrées (l'entrée est l'espace entre l'argument et la nouvelle ligne à la fin) et appelle ensuite la fonction write. sys.stdout est l’objet par défaut d’un objet donné, mais nous pouvons passer un fichier, c’est-à-dire que nous pouvons également imprimer l’entrée dans un fichier.

Python2: Si nous utilisons python2 alors

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

La virgule de fin Python2 est devenue un paramètre en Python3. Par conséquent, si nous utilisons des virgules de fin pour éviter le retour à la ligne après une impression, cela ressemblera à print ('Text to print', end = ''), ce qui constitue une erreur de syntaxe sous Python2. .

http://python3porting.com/noconv.html

Si nous vérifions pareil ci-dessus sceario en python3:

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

Sous Python 2.6, il y a une importation future pour imprimer dans une fonction. Donc, pour éviter les erreurs de syntaxe et autres différences, nous devrions commencer tous les fichiers dans lesquels nous utilisons print () avec future import print_function. L'importation future ne fonctionne que sous Python 2.6 et versions ultérieures. Par conséquent, pour Python 2.5 et versions antérieures, vous en avez deux. options. Vous pouvez convertir l’impression plus complexe en quelque chose de plus simple ou utiliser une fonction d’impression distincte fonctionnant sous Python2 et Python3.

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

Cas: Indiquez que sys.stderr.write () ou sys.stdout.write () (stdout (sortie standard) est un canal intégré à chaque système UNIX/Linux) ne remplace pas l'impression, mais oui. nous pouvons l'utiliser comme alternative dans certains cas. Print est un wrapper qui enveloppe l'entrée avec de l'espace et une nouvelle ligne à la fin et utilise la fonction write pour écrire. C'est la raison pour laquelle sys.stderr.write () est plus rapide.

Remarque: nous pouvons également suivre et déboguer à l'aide de la journalisation.

#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

0
Vinay Kumar

Essayer:

from sys import stderr


print >> sys.stderr, 'spam' 
0
Leon pvc