Python'da stderr'a nasıl yazdırılır?


1339

Stderr'e yazmanın birkaç yolu vardır:

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

Bu Python # 13 † ' in zeniyle çelişiyor gibi görünüyor , bu yüzden burada fark nedir ve şu ya da bu şekilde herhangi bir avantaj ya da dezavantaj var mı? Hangi yol kullanılmalı?

Bunu yapmanın bir - ve tercihen sadece bir - açık yolu olmalıdır.


46
Listelenen ilk yol, Python 3'te kaldırılan birçok şeyden biridir. Fikir birliği, >> sözdiziminin yine de çirkin olduğu ve baskı artık bir işlev olduğu için sözdizimi asla işe yaramayacak gibi görünüyor.
Steve Howard

23
Kullanıyorum: sys.exit ('Hata: <hata metni>')
stark

1
sadece print kullanın.
PythonMaster202

Yanıtlar:


1164

Bunu tek kısa + esnek + taşınabilir + okunabilir olarak buldum:

from __future__ import print_function
import sys

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

İşlev eprint, standart printişlevle aynı şekilde kullanılabilir :

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

29
Sadece bir düşünce: Bu, yazdırma işlevini içe aktaracağından, orijinal komut dosyasındaki diğer tüm "yazdır" öğelerinin artık "işlevselleştirilmesi" eklenmesi "(" ve ")" gerekir. Bu, bu yönteme karşı hafif bir grev, IMO.
Dan H

45
@DanH Evet bu sizi kodunuzu Python3 için hazır hale getirmeye zorlar . Sanırım pek çok insan aslında bundan hoşlanıyor olabilir!
MarcH

18
@MarkH ... evet, kodunuzu Python3 için hazır hale getirmeye zorlar ... aynı zamanda sizi ŞİMDİ yapmaya zorlar, sadece daha fazla güçlük bulacağınız stderr'e bazı hata ayıklama bilgilerini yazdırmak için ... bir şey hata ayıklamaya çalışırken çoğu durumda. (Yeni sözdizimi hataları vermemeyi tercih ederim!) :-)
Dan H

29
FWIW bu kod sizi programınızın işlev sürümünü kullanmaya zorlamazprint . Sadece tanımını içeren modülde eprint(). Tek başına küçük bir dosyaya koyun, dosyadan eprintdiğer dosyalarınıza aktarın ve ifadeyi printistediğiniz kadar kullanmaya devam edebilirsiniz .
alexis

3
Ayrıca baskıdan baskıya dönüştürme işlevi, 2to3'ün sizin için zaten otomatikleştirdiği basit bir keşiftir. Henüz yapmadıysanız yapın; python2 2 yıldan daha kısa bir sürede gider ... 2 ile 3 arasındaki bazı şeyler biraz zor olabilir; yazdırma işlevi bunlardan biri değil. Bkz. Docs.python.org/2/library/2to3.html
bobpaul

548
import sys
sys.stderr.write()

Benim seçimim, sadece daha okunabilir ve tam olarak ne yapmak istediğinizi söylüyor ve sürümler arasında taşınabilir.

Düzenleme: 'pitonik' olmak bana okunabilirlik ve performans üzerinde üçüncü bir düşünce ... bu iki şey göz önünde bulundurarak, kodunuzun% 80'i pitonik olacak. kavramanın sık kullanılmayan 'büyük şey' olduğunu listeler (okunabilirlik).


88
Sadece yıkamayı unutma.
temoto

10
İfadenin avantajı, printdize olmayan değerlerin önce dönüştürülmesine gerek kalmadan kolayca yazdırılmasıdır. Basılı bir ifadeye ihtiyacınız varsa, bu nedenle python 3'e hazır olmak için 3. seçeneği kullanmanızı öneririm
vdboor

56
sys.stderr.write()gibi bir şey değil print. Yeni satır eklemez.
Albay Panik

41
@temoto - stderr arabelleğe alınmaz, bu yüzden yıkamaya gerek yoktur.
Matt

11
@SkipHuffman Yani os.linesep. Bu stderrhepimizin sonra bahsediyoruz. Konsolun yanlış satırsonu ile uğraşmasını istemiyorum.
jpmc26

181

print >> sys.stderrPython3'te gitti. http://docs.python.org/3.0/whatsnew/3.0.html diyor ki:

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

Birçoğumuz için, varış noktasını komutanın sonuna devretmek biraz doğal değil. Alternatif

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

daha nesne yönelimli görünüyor ve zarif bir şekilde jenerikten spesifik olana doğru gidiyor. Ancak writebunun 1: 1 yerine geçmediğini unutmayın print.


5
Sanırım bu bir tercih meselesi, ama neyin çirkin olduğunu görmüyorum print('spam', file=sys.stderr). Bunu tekrar tekrar yapıyorsanız, 'eprint' işlevini en popüler yanıtta olduğu gibi kodlayabilirsiniz, ancak bu durumda, günlüklemeyle ilgili sorun nedir? stackoverflow.com/a/41304513/1450294
Michael Scheper

with sys.stderr as dest:print("ERROR", file=dest)
Niyeti

130

loggingHenüz kimseden bahsedilmedi , ancak günlük kaydı özellikle hata iletilerini iletmek için oluşturuldu. Temel yapılandırma stderr'a bir akış işleyici yazımı ayarlayacaktır.

Bu komut dosyası:

# foo.py
import logging

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

komut satırında çalıştırıldığında aşağıdaki sonucu verir:

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

ve bar.txt , stdout üzerine basılmış 'merhaba dünya'yı içerecektir.


2
Deneyimlerime göre, iletileri günlüğe kaydetmek için yazdırmayı kullanmaktan çok daha fazla kişi kullanıyor. Bence python4 sadece dilden baskı kaldırmak ve bunun için günlüğü kullanmaya zorlamanız gerekir.
Mnebuerquo

1
Bu en iyi cevap! ... baskı ya da sistemle uğraşıyordum ya da kim bilir ki uygun bir günlük kaydı gerektiğinde ... iyi fikir için teşekkürler
Carlos Saltos

129

İçin Python 2 benim seçimim: print >> sys.stderr, 'spam' basitçe dizesine dönüştürmek o olmadan vs listeleri / dicts yazdırabilirsiniz çünkü. print >> sys.stderr, {'spam': 'spam'} onun yerine: sys.stderr.write(str({'spam': 'spam'}))


6
Bir sözlük yazdırmanın daha çok Pythonic yolu "{0}".format({'spam': 'spam'})zaten böyle bir şeyle olur, değil mi? Açıkça dizeye dönüştürmekten kaçınmanız gerektiğini söyleyebilirim. Düzenleme: Yanlışlıkla bir dilbilgisi
luketparkinson

1
@luketparkinson bu hata ayıklama ile ilgili - bu yüzden, bence, mümkün olan en basit kodu kullanmak daha tercih edilir.
Frankovskyi Bogdan

88
Bu Python 3 üzerinde çalışmaz, bu yüzden yeni kodda kaçınmalısınız.
JonnyJD

33

Python 3 kullanarak aşağıdakileri yaptım:

from sys import stderr

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

Şimdi, örneğin, satır başını önlemek için anahtar kelime bağımsız değişkenleri ekleyebiliyorum:

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

2
Ben de kısmi kullanabileceğinizi önerecektim, ama kısmi kısmi yaratılış zamanında stderr işlevine atar. Bu, kısmi orijinal stderr nesnesini hala tutacağından stderr'ı daha sonra yönlendirmenizi önler.
Rebs

31

İlk yaklaşımınız:

print >> sys.stderr, 'spam' 

"Bir ... bunu yapmanın bariz yolu" Diğerleri 1 numaralı kurala uymuyor ("Güzel, çirkin olmaktan iyidir.")


109
Görüşler farklı. Bu benim için en az belirgin olanı .
porgarmingduod

4
@AliVeli Parantez yok, bu daha eski bir Python <= 2 sözdizimi ve bu nedenle Python 3 uyumlu değil.
Rebs

30
Bunun tüm çirkin en çirkin versiyonu olduğunu söyleyebilirim
volkan

4
>>Sözdizimsel olarak ne anlama geliyor? Bunun >, bash'ı kopyalamanın bir çabası olduğunu anlıyorum, bu yüzden bunu yapmak için ayakkabı bağı sözdizimi mi?
Dmytro Sirenko

2
@EarlGray C ++ 'ın akış ekleme operatörünün bir dayanak noktası:std::cout << "spam";
Sean Allred

19

Bu standart yazdırma işlevini taklit eder, ancak stderr'de çıktı alır

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

8
Bir sys.stderr.flush ()
AMS

4
@AMS - Neden? printfloş içermez.
Robᵩ

4
Gerçekte ne zaman yapabilirim?
Deli Fizikçi

19

Python 3'te print () kullanılabilir:

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

neredeyse kutunun dışında:

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

veya:

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

Bu basittir ve ayrıca bir şey içermesine gerek yoktur sys.stderr.


16

DÜZENLEME Arka görüşte, ben sys.stderr değiştirme ve güncelleştirilmiş davranış görmüyor olası karışıklığı düşünüyorum bu yanıtı sadece diğerlerinin işaret ettiği gibi basit bir işlevi kullanmak kadar iyi değil yapar.

Kısmi kullanmak yalnızca 1 satır kod kaydeder. Potansiyel karışıklık 1 satır kod kaydetmeye değmez.

orijinal

Bunu daha da kolaylaştırmak için, işlevlerin kaydırılmasında büyük bir yardımcı olan 'kısmi' kullanan bir sürüm.

from __future__ import print_function
import sys
from functools import partial

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

Daha sonra böyle kullanıyorsun

error('An error occured!')

Aşağıdakileri yaparak stderr'a yazdırıp stdout'a yazdırıp yazdırmadığını kontrol edebilirsiniz ( 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!")

Bunun dezavantajı kısmi olarak sys.stderr değerini yaratılış sırasındaki sarılmış işleve atar . Bu, stderr'ı daha sonra yönlendirirseniz , bu işlevi etkilemeyeceği anlamına gelir . Stderr'i yeniden yönlendirmeyi planlıyorsanız , bu sayfada aaguirre tarafından belirtilen ** kwargs yöntemini kullanın .


Corey Goldberg'in kodu en iyi Rube Goldberg makinesinde mi çalıştırılır? : P
Agi Çekiç

1
BTW: "kısmi", "kısmi" hakkında daha fazla bilgi edinmek istiyorsanız (daha) kullanışlı bir arama anahtar kelimesidir.
MarcH

5

Aynısı stdout için de geçerlidir:

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

Diğer yanıtlarda belirtildiği gibi, baskı genellikle daha kullanışlı (örneğin hata ayıklama bilgilerini yazdırmak için) hoş bir arayüz sunar, ancak yazma işlemi daha hızlıdır ve çıktıyı tam olarak belirli bir şekilde biçimlendirmeniz gerektiğinde daha uygun olabilir. Sürdürülebilirliği de göz önünde bulundururum:

  1. Daha sonra stdout / stderr ve normal bir dosya arasında geçiş yapmaya karar verebilirsiniz.

  2. Python 3'te print () sözdizimi değişti, bu nedenle her iki sürümü de desteklemeniz gerekiyorsa write () daha iyi olabilir.


4
Kullanmak from __future__ import print_function, hem Python 2.6+ hem de Python 3'ü desteklemek için daha iyi bir yoldur.
Phoenix

4

Python 3.4.3'te çalışıyorum. Buraya nasıl geldiğimi gösteren küçük bir yazı yazıyorum:

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

İşe yaradı mı? Stderr dosyasını bir dosyaya yönlendirmeyi deneyin ve ne olacağını görün:

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

Python'un size verdiği küçük tanıtımın stderr'e (başka nereye gidecekti?) Girmesi gerçeğinin yanı sıra, işe yarıyor.


2

Basit bir test yaparsanız:

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

Sys.stderr.write () yönteminin sürekli olarak 1.81 kez daha hızlı olduğunu göreceksiniz !


Bunu çalıştırırsam çok daha küçük bir fark görüyorum. Yanıtların çoğunun yazdırma işlevi (python 3) yolunu görmezden gelmesi ilginçtir. Daha önce hiç kullanmadım (atalet), ama bu zamanlama komut dosyasını çalıştırıp yazdırma işlevini ekleyeceğimi düşündüm. Yazdırma ifadesi ve işlevinin doğrudan karşılaştırılması mümkün değildir ( gelecekten içe aktarma tüm dosya için geçerlidir ve yazdırma ifadesini maskeler) ancak ifade yerine yazdırma işlevini kullanmak için bu kodu yeniden yazarken daha büyük bir hız görüyorum (biraz değişken olsa da ~ 1.6 ) yazdırma işlevi lehine.
hamish

1
Bu testin sonucu bir şekilde yanıltıcıdır. 'XXXXXXXXXXXXXXXXXXXX' yerine 'X' Baskı ve oranı düşer 1.05 . Çoğu python programının tek bir karakterden daha fazla yazdırması gerektiğini varsayıyorum.
Her zaman

14
Yazdırma uyarıları gibi bir şey için performansı umursamıyorum.
wim

Bir süre geçtiğini biliyorum, ama yazımdan sonra eşit derecede cevap verdiniz ... Performans hakkında araba kullanmıyorsanız, WTF'yi değil, sys.stderr.write'i kullanmak için daha pythonic bir yol olacağını öneririm!!? ">>" karakterleri. Bu sys.stdout ad alanı çok uzunsa, yeniden adlandırabilirsiniz ... (örn. Sys import stderr'den stderr_fh olarak). Sonra stderr_fh.write ("blah") yapabilirsiniz
ThePracticalOne

1
[3/3] Bu kıyaslama daha doğru olsa bile, muhtemelen endişelenmeye değmez. Knuth'un yazdığı gibi: "Programcılar, programlarının kritik olmayan bölümlerinin hızını düşünmek veya bunlardan endişe etmek için çok fazla zaman harcıyorlar ve bu verimlilik girişimlerinin hata ayıklama ve bakım sırasında gerçekten güçlü bir olumsuz etkisi olduğu düşünülmelidir. verimlilik, yani zamanın yaklaşık% 97'si: erken optimizasyon tüm kötülüklerin köküdür. "
Corey Goldberg

1

Önemli bir hata nedeniyle bir programdan çıkmak istiyorsanız, şunu kullanın:

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

ve import sysbaşlıkta.


-2

Sorunun cevabı: Stderr'i python'da yazdırmanın farklı bir yolu vardır, ancak bu 1.) hangi python sürümünü kullandığımızı 2.) tam olarak istediğimiz çıktı.

Yazdırma ve stderr'in yazma işlevi arasındaki fark: stderr : stderr (standart hata), programınız çöktüğünde ve hata ayıklama bilgilerini yazdırdığında (Python'daki bir izleme gibi), her UNIX / Linux sistemine yerleşik bir borudur. boru.

print : print, girdileri biçimlendiren bir sarıcıdır (girdi, argüman ile sondaki satırsonu arasındaki boşluktur) ve daha sonra belirli bir nesnenin yazma işlevini çağırır, varsayılan olarak verilen nesne sys.stdout'dur, ancak bir dosyayı iletmek yani girişi bir dosyaya da yazdırabiliriz.

Python2: Eğer python2 kullanıyorsanız

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

Python2 sondaki virgül Python3'te bir parametre haline gelir, bu nedenle bir baskıdan sonra yeni satırdan kaçınmak için sondaki virgül kullanırsak, bu Python3'te Python2 altında bir sözdizimi hatası olan yazdırma ('yazdırılacak metin', end = '') gibi görünür. .

http://python3porting.com/noconv.html

Python3'teki yukarıdaki sceario'yu kontrol edersek:

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

Python 2.6 altında , bir işleve baskı yapmak için gelecekteki bir içe aktarma vardır . Bu nedenle, sözdizimi hatalarını ve diğer farklılıkları önlemek için, print () işlevini kullandığımız herhangi bir dosyayı ileride import print_function ile başlatmamız gerekir . Gelecekteki ithalat sadece Python 2.6 altında çalışır ve daha sonra, bu yüzden Python 2.5 için ve önceki iki seçeneğiniz vardır. Daha karmaşık baskıyı daha basit bir şeye dönüştürebilir veya hem Python2 hem de Python3 altında çalışan ayrı bir yazdırma işlevi kullanabilirsiniz.

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

Durum: Dikkat edilmesi gereken nokta, sys.stderr.write () veya sys.stdout.write () (stdout (standart çıktı), her UNIX / Linux sistemine yerleşik bir borudır) yazdırma yerine geçmez, ancak evet bazı durumlarda alternatif olarak kullanabiliriz. Yazdır, girdiyi sonunda boşluk ve satırsonu ile saran ve yazmak için yazma işlevini kullanan bir sarıcıdır. Sys.stderr.write () yönteminin daha hızlı olmasının nedeni budur.

Not: Günlük Kaydı kullanarak da izleyebilir ve hata ayıklayabiliriz

#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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.