Jak drukować na stderr w Pythonie?


1338

Istnieje kilka sposobów pisania na 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)

To wydaje się być sprzeczne z zen z Pythona nr 13 , więc jaka jest tutaj różnica i czy są jakieś zalety lub wady w ten czy inny sposób? Który sposób należy zastosować?

Powinien istnieć jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego.


46
Pierwszy sposób wymieniony na liście to jedna z wielu rzeczy usuniętych w Pythonie 3. Konsensus wydaje się być taki, że i tak składnia >> była brzydka, a ponieważ print jest teraz funkcją, składnia nigdy nie zadziała.
Steve Howard,

23
Używam: sys.exit ('Error: <error text>')
surowy

1
po prostu użyj drukowania.
PythonMaster202,

Odpowiedzi:


1165

Odkryłem, że jest to jedyny krótki + elastyczny + przenośny + czytelny:

from __future__ import print_function
import sys

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

Z funkcji eprintmożna korzystać tak samo, jak w przypadku printfunkcji standardowej :

>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz

29
Jedna myśl: ponieważ spowoduje to zaimportowanie funkcji drukowania, każdy inny „print” w oryginalnym skrypcie będzie musiał zostać „funkcjonalizowany” przez dodanie „(” i „)”. Jest to więc niewielkie uderzenie w tę metodę, IMO.
Dan H

45
@DanH Tak, to zmusza cię do przygotowania kodu Python3. Myślę, że to może być powód, dla którego wielu ludzi to lubi!
MarcH

18
@MarkH ... tak, zmusza cię do przygotowania kodu Python3 ... zmusza cię do zrobienia tego TERAZ, po prostu do wydrukowania informacji o debugowaniu na stderr ... co byłoby dla mnie większym problemem większość sytuacji, gdy próbuję coś debugować. (Wolałbym nie wprowadzać nowych błędów składniowych!) :-)
Dan H

29
FWIW ten kod nie zmusza cię do używania wersji funkcji printw całym programie. Tylko w module zawierającym definicję eprint(). Umieść go sam w małym pliku, zaimportuj eprintz niego do innych plików, a będziesz mógł używać instrukcji printtak długo, jak chcesz.
Alexis

3
Również przejście z funkcji drukowania do drukowania jest prostym znaleziskiem, które 2to3 już zautomatyzuje. Po prostu zrób to już, jeśli nie masz; Python2 zniknie za niecałe 2 lata ... Niektóre rzeczy między 2 a 3 mogą być nieco trudne; funkcja drukowania nie jest jedną z nich. Zobacz docs.python.org/2/library/2to3.html
bobpaul

548
import sys
sys.stderr.write()

To mój wybór, tylko bardziej czytelny i mówiący dokładnie, co zamierzasz robić, i przenośny w różnych wersjach.

Edycja: bycie „pytonicznym” to dla mnie trzecia myśl na temat czytelności i wydajności ... mając na uwadze te dwie rzeczy, z pythonem 80% twojego kodu będzie pytoniczne. rozumienie listy jest „wielką rzeczą”, która nie jest używana tak często (czytelność).


88
Tylko nie zapomnij spłukać.
Temoto

10
Zaletą printinstrukcji jest łatwe drukowanie wartości nieciągłych, bez konieczności ich wcześniejszej konwersji. Jeśli potrzebujesz instrukcji print,
zaleciłbym

56
sys.stderr.write()jest niczym print. Nie dodaje nowej linii.
Pułkownik Panika

41
@temoto - stderr nie jest buforowany, więc nie ma potrzeby spłukiwania.
Matt

11
@SkipHuffman Masz na myśli os.linesep. W stderrkońcu o tym mówimy. Nie chcę, aby konsola zepsuła się z niewłaściwym nowym wierszem.
jpmc26

179

print >> sys.stderrzniknął w Python3. http://docs.python.org/3.0/whatsnew/3.0.html mówi:

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

Dla wielu z nas przeniesienie miejsca docelowego na koniec polecenia wydaje się nieco nienaturalne. Alternatywa

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

wygląda bardziej obiektowo i elegancko przechodzi od ogólnej do szczegółowej. Pamiętaj jednak, że writenie jest to zamiennik 1: 1 dla print.


5
Przypuszczam, że to kwestia preferencji, ale nie rozumiem, co jest brzydkiego print('spam', file=sys.stderr). Jeśli robisz to w kółko, możesz zakodować funkcję „eprint” jak w najpopularniejszej odpowiedzi, ale w takim przypadku zapytałbym, co jest nie tak z logowaniem? stackoverflow.com/a/41304513/1450294
Michael Scheper

Innym sposobem wyjaśnienia zamiaru byłoby zrobienie with sys.stderr as dest:przed wciętym wezwaniem doprint("ERROR", file=dest)
MarkHu

130

Nikt loggingjeszcze nie wspomniano , ale rejestrowanie zostało utworzone specjalnie w celu przekazywania komunikatów o błędach. Podstawowa konfiguracja skonfiguruje obsługę strumienia zapisującą do stderr.

Ten skrypt:

# foo.py
import logging

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

ma następujący wynik po uruchomieniu w wierszu poleceń:

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

i bar.txt będzie zawierać „hello world” wydrukowany na standardowym wyjściu.


2
Z mojego doświadczenia wynika, że ​​więcej osób używa drukowania do rejestrowania wiadomości niż korzystania z rejestrowania. Myślę, że python4 powinien po prostu usunąć druk z języka i zmusić cię do korzystania z logowania.
Mnebuerquo

1
To najlepsza odpowiedź !! ... walczyłem z drukiem lub sys lub kto wie ... kiedy potrzebne jest prawidłowe logowanie ... dzięki za dobry pomysł
Carlos Saltos

129

W przypadku Pythona 2 mój wybór to: print >> sys.stderr, 'spam' Ponieważ możesz po prostu wydrukować listy / dykty itp. Bez konwersji na ciąg znaków. print >> sys.stderr, {'spam': 'spam'} zamiast: sys.stderr.write(str({'spam': 'spam'}))


6
W każdym razie bardziej Pythoniczny sposób wydrukowania słownika byłby taki "{0}".format({'spam': 'spam'}), prawda? Powiedziałbym, że powinieneś unikać jawnej konwersji na ciąg. Edycja: I przypadkowo gramatyka
luketparkinson

1
@ Phuketparkinson to wszystko dotyczy debugowania - więc myślę, że lepiej jest użyć najprostszego kodu, jak to możliwe.
Frankovskyi Bogdan

88
To nie działa w Pythonie 3, więc powinieneś tego unikać w nowym kodzie.
JonnyJD

33

Zrobiłem następujące przy użyciu Python 3:

from sys import stderr

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

Teraz mogę dodać na przykład argumenty słów kluczowych, aby uniknąć powrotu karetki:

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

2
Chciałem zasugerować, że można również użyć częściowego, ale zdałem sobie sprawę, że częściowy przypisuje stderr do funkcji w czasie tworzenia częściowego. Zapobiega to późniejszemu przekierowaniu stderr, ponieważ częściowa nadal będzie zawierać oryginalny obiekt stderr.
Rebs

31

Powiedziałbym, że twoje pierwsze podejście:

print >> sys.stderr, 'spam' 

to „Jeden ... oczywisty sposób na to” Inni nie spełniają zasady nr 1 („Piękne jest lepsze niż brzydkie”)


109
Opinie się różnią. To jest dla mnie najmniej oczywiste .
porgarmingduod

4
@AliVeli Nie ma nawiasów, jest to starsza składnia języka Python <= 2, a zatem nie jest kompatybilna z językiem Python 3.
Rebs

30
Powiedziałbym, że jest to najbrzydsza wersja wszystkich 3
wulkanów

4
Co to >>oznacza składniowo? Rozumiem, że jest to próba skopiowania basha >, więc czy jest to jakaś składnia typu boothorned?
Dmytro Sirenko

2
@EarlGray Jest to pozostałość po operatorze wstawiania strumienia C ++:std::cout << "spam";
Sean Allred

19

To naśladuje standardową funkcję drukowania, ale wyświetla na stderr

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

8
Dodałbym sys.stderr.flush ()
AMS

4
@AMS - Dlaczego? printnie obejmuje koloru.
Robᵩ

4
Po co naśladować, skoro możesz to zrobić?
Szalony fizyk

19

W Pythonie 3 można po prostu użyć print ():

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

prawie po wyjęciu z pudełka:

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

lub:

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

Jest to proste i nie musi zawierać niczego poza sys.stderr.


16

EDYCJA Z perspektywy czasu myślę, że potencjalne zamieszanie związane ze zmianą sys.stderr i brakiem aktualizacji zachowania powoduje, że ta odpowiedź nie jest tak dobra, jak zwykła funkcja, jak zauważyli inni.

Użycie tylko częściowego oszczędza 1 linię kodu. Potencjalne zamieszanie nie jest warte zapisania 1 linii kodu.

oryginalny

Aby było to jeszcze łatwiejsze, oto wersja, która używa „częściowego”, co stanowi dużą pomoc w zawijaniu funkcji.

from __future__ import print_function
import sys
from functools import partial

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

Następnie używasz go w ten sposób

error('An error occured!')

Możesz sprawdzić, czy drukuje na stderr, a nie na stdout, wykonując następujące czynności (nadrzędny kod z 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!")

Minusem tego jest częściowe przypisanie wartości sys.stderr do zawiniętej funkcji w momencie tworzenia. Co oznacza, że jeśli przekierujesz stderr później, nie wpłynie to na tę funkcję. Jeśli planujesz przekierować stderr, użyj ** metody kwargs wspomnianej przez aaguirre na tej stronie.


Czy kod Corey Goldberg najlepiej działa na maszynie Rube Goldberg? : P
Agi Hammerthief,

1
BTW: „curry” jest (bardziej) przydatnym słowem kluczowym do wyszukiwania, jeśli chcesz dowiedzieć się więcej o „częściowym”.
MarcH

5

To samo dotyczy standardowego wyjścia:

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

Jak stwierdzono w innych odpowiedziach, print oferuje ładny interfejs, który jest często wygodniejszy (np. Do drukowania informacji debugowania), podczas gdy zapis jest szybszy i może być również wygodniejszy, gdy trzeba sformatować dane wyjściowe dokładnie w określony sposób. Rozważałbym również łatwość konserwacji:

  1. Możesz później zdecydować się na przełączenie między stdout / stderr a zwykłym plikiem.

  2. Składnia print () zmieniła się w Pythonie 3, więc jeśli potrzebujesz obsługiwać obie wersje, write () może być lepszy.


4
Korzystanie from __future__ import print_functionjest lepszym sposobem na obsługę zarówno Python 2.6+, jak i Python 3.
Phoenix

4

Pracuję w Pythonie 3.4.3. Wycinam trochę pisania, które pokazuje, jak się tu dostałem:

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

Zadziałało? Spróbuj przekierować stderr do pliku i zobacz, co się stanie:

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

Cóż, poza tym, że małe wprowadzenie, które daje ci Python, zostało zawieszone w stderr (gdzie indziej by poszło?), Działa.


2

Jeśli wykonasz prosty test:

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

Przekonasz się, że sys.stderr.write () jest konsekwentnie 1,81 razy szybszy!


Jeśli to uruchomię, zauważę znacznie mniejszą różnicę. Interesujące jest to, że większość odpowiedzi ignoruje sposób drukowania (python 3). Nigdy wcześniej go nie używałem (bezwładność), ale pomyślałem, że uruchomię ten skrypt pomiaru czasu i dodam funkcję drukowania. Bezpośrednie porównanie instrukcji print i funkcji nie jest możliwe (import z przyszłości dotyczy całego pliku i maskuje instrukcję print), ale przepisanie tego kodu w celu użycia funkcji print zamiast instrukcji widzę większe przyspieszenie (~ 1.6, choć nieco zmienne ) na korzyść funkcji drukowania.
hamish

1
Wynik tego testu jest niejasny. Wydrukuj „XXXXXXXXXXXXXXXXXXXX” zamiast „X”, a stosunek spadnie do 1,05 . Zakładam, że większość programów w Pythonie musi drukować więcej niż jeden znak.
Zawsze pytam

14
Nie dbam o wydajność, na przykład o drukowanie ostrzeżeń.
wim

Wiem, że minęło trochę czasu, ale odpowiedziałeś równie długo po moim poście ... Jeśli nie zależy ci na wydajności, sugerowałbym, że bardziej pythonicznym sposobem byłoby użycie sys.stderr.write, a nie WTF?!? Znaki „>>”. Jeśli ta przestrzeń nazw sys.stdout jest zbyt długa, możesz zmienić jej nazwę ... (tzn. Z sys importuj stderr jako stderr_fh). Następnie możesz zrobić stderr_fh.write ("blah")
ThePracticalOne

1
[3/3] Nawet jeśli ten test porównawczy był dokładniejszy, prawdopodobnie nie warto się martwić. Jak napisał Knuth: „Programiści marnują mnóstwo czasu na myślenie lub martwienie się o szybkość niekrytycznych części swoich programów, a te próby wydajności mają silny negatywny wpływ na debugowanie i konserwację. Powinniśmy zapomnieć o małych wydajność, powiedzmy w 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła ”.
Corey Goldberg,

1

Jeśli chcesz wyjść z programu z powodu błędu krytycznego, użyj:

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

i import sysw nagłówku.


-2

Odpowiedź na pytanie brzmi: Istnieje inny sposób wypisywania stderr w pythonie, ale to zależy od 1.) której wersji python używamy 2.) jakiego dokładnego wyniku chcemy.

Różnica między funkcją drukowania a funkcją zapisu stderr : stderr : stderr (błąd standardowy) jest potokiem wbudowanym w każdy system UNIX / Linux, gdy twój program ulega awarii i drukuje informacje debugowania (jak traceback w Pythonie), przechodzi do stderr rura.

print : print to opakowanie, które formatuje dane wejściowe (dane wejściowe to spacja między argumentem a znakiem nowej linii na końcu), a następnie wywołuje funkcję zapisu danego obiektu, domyślnie dany obiekt to sys.stdout, ale możemy przekazać plik, tzn. możemy również wydrukować dane wejściowe w pliku.

Python2: Jeśli więc używamy Python2

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

Końcowy przecinek w Python2 stał się w Python3 parametrem, więc jeśli użyjemy przecinków końcowych, aby uniknąć nowej linii po wydruku, w Python3 będzie to wyglądać jak print („Text to print”, end = ''), co jest błędem składniowym w Python2 .

http://python3porting.com/noconv.html

Jeśli sprawdzimy to samo powyżej sceario w python3:

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

W Pythonie 2.6 istnieje przyszły import umożliwiający drukowanie w funkcji. Aby uniknąć błędów składniowych i innych różnic, powinniśmy uruchomić każdy plik, w którym używamy print (), z przyszłego importu print_function. Przyszłość import działa tylko pod Pythona 2.6 i później, tak dla Pythona 2.5 i wcześniejszych masz dwie opcje. Możesz przekształcić bardziej złożony druk w coś prostszego lub możesz użyć oddzielnej funkcji drukowania, która działa zarówno w Python2, jak i Python3.

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

Przypadek: Należy zauważyć, że sys.stderr.write () lub sys.stdout.write () (stdout (standardowe wyjście) jest potokiem wbudowanym w każdy system UNIX / Linux) nie zastępuje drukowania, ale tak w niektórych przypadkach możemy go użyć jako alternatywy. Print to opakowanie, które otacza wejście spacją i znakiem nowej linii na końcu i używa funkcji write do pisania. Z tego powodu sys.stderr.write () jest szybszy.

Uwaga: możemy również śledzić i debugować za pomocą Rejestrowania

#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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.