Wie drucke ich in Python auf stderr?

1339

Es gibt verschiedene Möglichkeiten, an stderr zu schreiben:

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

Das scheint dem Zen von Python # 13 zu widersprechen. Was ist hier also der Unterschied und gibt es auf die eine oder andere Weise Vor- oder Nachteile? Welcher Weg sollte verwendet werden?

Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun.

wim
quelle
46
Der erste aufgeführte Weg ist einer der vielen Dinge, die in Python 3 entfernt wurden. Der Konsens scheint zu sein, dass die >> Syntax sowieso hässlich war, und da print jetzt eine Funktion ist, würde die Syntax niemals funktionieren.
Steve Howard
23
Ich benutze: sys.exit ('Fehler: <Fehlertext>')
stark
1
benutze einfach print.
PythonMaster202

Antworten:

1164

Ich fand dies die einzige kurze + flexible + tragbare + lesbare:

from __future__ import print_function
import sys

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

Die Funktion eprintkann auf die gleiche Weise wie die Standardfunktion verwendet printwerden:

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
März
quelle
29
Nur ein Gedanke: Da dies die Druckfunktion importiert, muss jetzt jeder zweite "Druck" im ursprünglichen Skript "funktionalisiert" werden, indem "(" und ")" hinzugefügt wird. Das ist also ein leichter Schlag gegen diese Methode, IMO.
Dan H
45
@DanH Ja, dies zwingt Sie dazu, Ihren Code Python3-fähig zu machen. Ich denke, das könnte der Grund sein, warum es vielen Leuten wirklich gefällt!
MarcH
18
@MarkH ... ja, es zwingt Sie dazu, Ihren Code Python3-fähig zu machen ... es zwingt Sie auch dazu, es JETZT zu tun, nur um einige Debugging-Informationen an den stderr zu drucken ... was ich eher als problematisch empfinden würde Die meisten Situationen, in denen ich versuche, etwas zu debuggen. (Ich möchte lieber keine neuen Syntaxfehler einführen!) :-)
Dan H
29
FWIW dieser Code nicht zwingen Sie die Funktion Version zu verwenden , printin dem gesamten Programm. Nur in dem Modul, das die Definition von enthält eprint(). Legen Sie es selbst in eine kleine Datei, importieren Sie eprintes in Ihre anderen Dateien, und Sie können die Anweisung printso lange verwenden, wie Sie möchten.
Alexis
3
Auch das Konvertieren von Druck- in Druckfunktion ist ein einfacher Suchersatz, den 2to3 bereits für Sie automatisiert. Mach es einfach schon, wenn du es nicht getan hast. python2 wird in weniger als 2 Jahren verschwunden sein ... Einige Dinge zwischen 2 und 3 können etwas schwierig werden; Druckfunktion ist keine davon. Siehe docs.python.org/2/library/2to3.html
Bobpaul
548
import sys
sys.stderr.write()

Ist meine Wahl, nur besser lesbar und genau das zu sagen, was Sie vorhaben, und über Versionen hinweg portierbar.

Bearbeiten: "Pythonisch" zu sein, ist für mich ein dritter Gedanke in Bezug auf Lesbarkeit und Leistung. In Anbetracht dieser beiden Aspekte werden bei Python 80% Ihres Codes pythonisch sein. Listenverständnis ist das "große Ding", das nicht so oft verwendet wird (Lesbarkeit).

Mike Ramirez
quelle
88
Vergiss nur nicht zu spülen.
Temoto
10
Der Vorteil der printAnweisung ist das einfache Drucken von Nicht-String-Werten, ohne dass diese zuerst konvertiert werden müssen. Wenn Sie eine
Druckanweisung
56
sys.stderr.write()ist nichts wie print. Es wird keine neue Zeile hinzugefügt.
Colonel Panic
41
@temoto - stderr ist nicht gepuffert, daher muss nicht gespült werden.
Matt
11
@ SkipHuffman Du meinst os.linesep. Das ist stderres doch, worüber wir reden. Ich möchte nicht, dass die Konsole den falschen Zeilenumbruch durcheinander bringt.
jpmc26
182

print >> sys.stderrist in Python3 weg. http://docs.python.org/3.0/whatsnew/3.0.html sagt:

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

Für viele von uns ist es etwas unnatürlich, das Ziel bis zum Ende des Befehls zu verbannen. Die Alternative

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

sieht objektorientierter aus und geht elegant vom Generischen zum Spezifischen. Beachten Sie jedoch, dass dies writekein 1: 1-Ersatz für ist print.

Joachim W.
quelle
6
Ich nehme an, es ist eine Frage der Präferenz, aber ich sehe nicht, was hässlich ist print('spam', file=sys.stderr). Wenn Sie es immer und immer wieder tun, können Sie die 'eprint'-Funktion wie in der beliebtesten Antwort codieren, aber in diesem Fall würde ich fragen, was ist falsch an der Protokollierung? stackoverflow.com/a/41304513/1450294
Michael Scheper
Eine andere Möglichkeit, die Absicht zu klären, wäre, with sys.stderr as dest:vor einem eingerückten Anruf anprint("ERROR", file=dest)
MarkHu
130

Bisher wurde loggingnoch niemand erwähnt , aber die Protokollierung wurde speziell für die Übermittlung von Fehlermeldungen erstellt. Durch die Grundkonfiguration wird ein Stream-Handler eingerichtet, der in stderr schreibt.

Dieses Skript:

# foo.py
import logging

logging.basicConfig(format='%(message)s')
log = logging.getLogger(__name__)
log.warning('I print to stderr by default')
print('hello world')

hat das folgende Ergebnis, wenn es in der Befehlszeile ausgeführt wird:

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

und bar.txt enthält die auf stdout gedruckte 'Hallo Welt'.

matschig
quelle
2
Nach meiner Erfahrung verwenden mehr Menschen Druck, um Nachrichten zu protokollieren, als Protokollierung. Ich denke, Python4 sollte nur den Druck aus der Sprache entfernen und Sie dazu zwingen, die Protokollierung dafür zu verwenden.
Mnebuerquo
1
Das ist die beste Antwort !! ... Ich hatte Probleme mit Print oder Sys oder wer weiß ... wann eine ordnungsgemäße Protokollierung erforderlich ist ... Danke für die gute Idee
Carlos Saltos
129

Für Python 2 habe ich die Wahl: print >> sys.stderr, 'spam' Weil Sie einfach Listen / Diktate usw. drucken können, ohne sie in einen String umzuwandeln. print >> sys.stderr, {'spam': 'spam'} anstatt: sys.stderr.write(str({'spam': 'spam'}))

Frankovskyi Bogdan
quelle
6
Die pythonischere Art, ein Wörterbuch zu drucken "{0}".format({'spam': 'spam'}), wäre sowieso so etwas , oder? Ich würde sagen, Sie sollten es vermeiden, explizit in einen String zu konvertieren. Edit: Ich habe versehentlich eine Grammatik
luketparkinson
1
@luketparkinson hier dreht sich alles um das Debuggen - daher ist es meiner Meinung nach besser, den einfachsten Code als möglich zu verwenden.
Frankovskyi Bogdan
88
Dies funktioniert unter Python 3 nicht, daher sollten Sie es in neuem Code vermeiden.
JonnyJD
33

Ich habe Folgendes mit Python 3 gemacht:

from sys import stderr

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

Jetzt kann ich beispielsweise Schlüsselwortargumente hinzufügen, um Wagenrücklauf zu vermeiden:

print_err("Error: end of the file reached. The word ", end='')
print_err(word, "was not found")
aaguirre
quelle
2
Ich wollte vorschlagen, dass Sie auch einen Teil verwenden können, stellte jedoch fest, dass der Teil zum Zeitpunkt der Erstellung des Teils der Funktion stderr zuweist. Dies verhindert, dass Sie stderr später umleiten, da der Teil weiterhin das ursprüngliche stderr-Objekt enthält.
Rebs
31

Ich würde sagen, dass Ihr erster Ansatz:

print >> sys.stderr, 'spam' 

ist der "Eine ... offensichtliche Weg, es zu tun" Die anderen erfüllen Regel 1 nicht ("Schön ist besser als hässlich.")

Carl F.
quelle
109
Die Meinungen sind unterschiedlich. Das ist mir am wenigsten klar .
Porgarmingduod
4
@AliVeli Es gibt keine Klammern, dies ist eine ältere Python <= 2-Syntax und daher nicht Python 3-kompatibel.
Rebs
30
Ich würde sagen, dass dies die hässlichste Version aller 3
Vulkan
4
Was bedeutet das >>syntaktisch? Ich verstehe, dass es eine Anstrengung ist, Bashs zu kopieren. Ist >es also eine Schuhlöffel-Syntax, genau das zu tun?
Dmytro Sirenko
2
@EarlGray Es ist ein Überbleibsel von C ++ 's Stream Insertion Operator:std::cout << "spam";
Sean Allred
19

Dies ahmt die Standarddruckfunktion nach, wird jedoch auf stderr ausgegeben

def print_err(*args):
    sys.stderr.write(' '.join(map(str,args)) + '\n')
Brian W.
quelle
8
Ich würde ein sys.stderr.flush ()
AMS
4
@AMS - Warum? printbeinhaltet keine Spülung.
Robᵩ
4
Warum nachahmen, wenn Sie es tatsächlich können?
Mad Physicist
19

In Python 3 kann man einfach print () verwenden:

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

fast out of the box:

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

oder:

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

Dies ist unkompliziert und muss nichts anderes enthalten sys.stderr.

Florian Castellane
quelle
16

BEARBEITEN Im Nachhinein denke ich, dass die mögliche Verwechslung mit dem Ändern von sys.stderr und dem Nicht-Aktualisieren des Verhaltens dazu führt, dass diese Antwort nicht so gut ist, wie nur eine einfache Funktion zu verwenden, wie andere darauf hingewiesen haben.

Wenn Sie teilweise verwenden, sparen Sie nur 1 Codezeile. Die mögliche Verwirrung ist es nicht wert, 1 Codezeile zu speichern.

Original

Um es noch einfacher zu machen, gibt es hier eine Version, die 'partiell' verwendet, was eine große Hilfe beim Umschließen von Funktionen ist.

from __future__ import print_function
import sys
from functools import partial

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

Sie verwenden es dann so

error('An error occured!')

Sie können überprüfen, ob es auf stderr und nicht auf stdout gedruckt wird, indem Sie die folgenden Schritte ausführen (übergeordneter Code von 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!")

Der Nachteil ist , teilweise Abtretungs den Wert sys.stderr zur gewickelten Funktion zum Zeitpunkt der Erstellung. Das heißt, wenn Sie stderr später umleiten, wird diese Funktion nicht beeinträchtigt. Wenn Sie stderr umleiten möchten, verwenden Sie die von aaguirre auf dieser Seite erwähnte ** kwargs-Methode .

Rebs
quelle
Läuft der Code von Corey Goldberg am besten auf einer Rube Goldberg-Maschine? : P
Agi Hammerthief
1
Übrigens: "Currying" ist ein (nützlicheres) Suchwort, wenn Sie mehr über "partiell" erfahren möchten.
MarcH
5

Gleiches gilt für stdout:

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

Wie in den anderen Antworten angegeben, bietet print eine hübsche Oberfläche, die häufig bequemer ist (z. B. zum Drucken von Debug-Informationen), während das Schreiben schneller ist und auch bequemer sein kann, wenn Sie die Ausgabe auf bestimmte Weise genau formatieren müssen. Ich würde auch die Wartbarkeit in Betracht ziehen:

  1. Sie können später entscheiden, zwischen stdout / stderr und einer regulären Datei zu wechseln.

  2. Die Syntax von print () hat sich in Python 3 geändert. Wenn Sie also beide Versionen unterstützen müssen, ist write () möglicherweise besser.

Seppo Enarvi
quelle
4
Die Verwendung from __future__ import print_functionist eine bessere Möglichkeit, sowohl Python 2.6+ als auch Python 3 zu unterstützen.
Phoenix
4

Ich arbeite in Python 3.4.3. Ich schneide eine kleine Eingabe aus, die zeigt, wie ich hierher gekommen bin:

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

Hat es funktioniert? Versuchen Sie, stderr in eine Datei umzuleiten, und sehen Sie, was passiert:

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

Nun, abgesehen von der Tatsache, dass die kleine Einführung, die Python Ihnen gibt, in stderr geschlürft wurde (wohin würde es sonst gehen?), Funktioniert es.

user1928764
quelle
2

Wenn Sie einen einfachen Test durchführen:

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

Sie werden feststellen, dass sys.stderr.write () durchweg 1,81- mal schneller ist!

ThePracticalOne
quelle
Wenn ich das mache, sehe ich einen viel kleineren Unterschied. Es ist interessant, dass die meisten Antworten die Druckfunktion (Python 3) ignorieren. Ich habe es noch nie benutzt (Trägheit), dachte aber, ich würde dieses Timing-Skript ausführen und die Druckfunktion hinzufügen. Ein direkter Vergleich von print-Anweisung und -Funktion ist nicht möglich (Import aus der Zukunft gilt für die gesamte Datei und maskiert die print-Anweisung), aber wenn Sie diesen Code neu schreiben, um die print-Funktion anstelle der Anweisung zu verwenden, sehe ich eine größere Beschleunigung (~ 1,6, wenn auch etwas variabel) ) zugunsten der Druckfunktion.
Hamish
1
Das Ergebnis dieses Tests ist irgendwie irreführend. Drucken Sie 'XXXXXXXXXXXXXXXXXXXX' anstelle von 'X' und das Verhältnis sinkt auf 1,05 . Ich gehe davon aus, dass die meisten Python-Programme mehr als ein einzelnes Zeichen drucken müssen.
Immer fragen
14
Die Leistung ist mir egal, zum Beispiel das Drucken von Warnungen.
wim
Ich weiß, dass es eine Weile her ist, aber Sie haben genauso lange nach meinem Beitrag geantwortet ... Wenn Sie sich nicht um die Leistung kümmern, würde ich vorschlagen, dass der pythonischere Weg darin besteht, sys.stderr.write und nicht die WTF zu verwenden?!? ">>" Zeichen. Wenn dieser Namespace sys.stdout zu lang ist, können Sie ihn umbenennen ... (dh von sys import stderr als stderr_fh). Dann können Sie stderr_fh.write ("blah")
ThePracticalOne
1
[3/3] Auch wenn dieser Benchmark genauer wäre, lohnt es sich wahrscheinlich nicht, sich darüber Sorgen zu machen. Wie Knuth schrieb: "Programmierer verschwenden enorm viel Zeit damit, über die Geschwindigkeit unkritischer Teile ihrer Programme nachzudenken oder sich darüber Gedanken zu machen, und diese Effizienzversuche wirken sich tatsächlich stark negativ aus, wenn Debugging und Wartung in Betracht gezogen werden. Wir sollten kleine vergessen." Effizienz, sagen wir etwa 97% der Zeit: Vorzeitige Optimierung ist die Wurzel allen Übels. "
Corey Goldberg
1

Wenn Sie ein Programm aufgrund eines schwerwiegenden Fehlers beenden möchten, verwenden Sie:

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

und import sysin der Kopfzeile.

feli_x
quelle
-2

Die Antwort auf die Frage lautet: Es gibt verschiedene Möglichkeiten, stderr in Python zu drucken, aber das hängt davon ab, 1.) welche Python-Version wir verwenden 2.) welche genaue Ausgabe wir wollen.

Der Unterschied zwischen print und der Schreibfunktion von stderr : stderr : stderr (Standardfehler) ist eine Pipe, die in jedes UNIX / Linux-System integriert ist. Wenn Ihr Programm abstürzt und Debugging-Informationen ausgibt (wie ein Traceback in Python), geht es an stderr Rohr.

print : print ist ein Wrapper, der die Eingaben formatiert (die Eingabe ist das Leerzeichen zwischen Argument und Zeilenumbruch am Ende) und dann die Schreibfunktion eines bestimmten Objekts aufruft. Das angegebene Objekt ist standardmäßig sys.stdout, aber wir können Übergeben Sie eine Datei, dh wir können die Eingabe auch in einer Datei drucken.

Python2: Wenn wir dann Python2 verwenden

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

Das nachgestellte Python2-Komma ist in Python3 zu einem Parameter geworden. Wenn wir also nach dem Drucken nachgestellte Kommas verwenden, um die neue Zeile zu vermeiden, sieht dies in Python3 wie print aus ('Text zum Drucken', end = ''), was unter Python2 ein Syntaxfehler ist .

http://python3porting.com/noconv.html

Wenn wir dasselbe oben in Python3 überprüfen:

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

Unter Python 2.6 gibt es einen zukünftigen Import, um den Druck in eine Funktion zu verwandeln. Um Syntaxfehler und andere Unterschiede zu vermeiden, sollten wir jede Datei, in der wir print () verwenden, mit einer zukünftigen import print_function starten. Der zukünftige Import funktioniert nur unter Python 2.6 und höher. Für Python 2.5 und frühere Versionen stehen Ihnen zwei Optionen zur Verfügung. Sie können entweder den komplexeren Druck in etwas Einfacheres konvertieren oder eine separate Druckfunktion verwenden, die sowohl unter Python2 als auch unter Python3 funktioniert.

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

Fall: Beachten Sie, dass sys.stderr.write () oder sys.stdout.write () (stdout (Standardausgabe) ist eine Pipe, die in jedes UNIX / Linux-System integriert ist) kein Ersatz für print ist, aber ja wir können es in einigen Fällen als Alternative verwenden. Print ist ein Wrapper, der die Eingabe am Ende mit Leerzeichen und Zeilenumbruch umschließt und zum Schreiben die Schreibfunktion verwendet. Dies ist der Grund, warum sys.stderr.write () schneller ist.

Hinweis: Wir können das Protokollieren und Debuggen auch mithilfe der Protokollierung durchführen

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