2014-11-01 36 views
14

Soru: BrokenPipeError'u almadan print() işlevi için flush=True işlevini kullanmanın bir yolu var mı?Python'da BrokenPipeError

for i in range(4000): 
    print(i) 

Bir Unix komut satırından böyle diyoruz:

python3 pipe.py | head -n3000 

Ve döndürür:

0 
1 
2 

Yani bu senaryoyu yapar

, bir senaryonun pipe.py var :

Ben head -n3000 için bu senaryoyu ve boru çalıştırıldığı zaman

Ancak: Sonra

for i in range(4000): 
    print(i, flush=True) 

bu hatayı alıyorum: Ben de çözüm aşağıda çalıştık

print(i, flush=True) 
BrokenPipeError: [Errno 32] Broken pipe 
Exception BrokenPipeError: BrokenPipeError(32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored 

, ama hala olsun BrokenPipeError:

import sys 
for i in range(4000): 
    try: 
     print(i, flush=True) 
    except BrokenPipeError: 
     sys.exit() 
+0

OS X 10.1'de yeniden oluşturamıyorum 0, şimdi CentOS 6.6'yı deniyorum. – jgritty

+0

Sadece OS X 10.9.4'ü denedim ve onu yeniden üretemedim. Ubuntu 12.04.2 LTS'de hatayı aldım. Linux Mint Qiana'yı deneyeceğim. –

+0

Tüm komut dosyalarınız benim için kırılsın, ilk önce ... – phantom

cevap

13

BrokenPipeError normaldir: vaka Eğer kapatmawrite ve flush fonksiyonu ve istisna tetiklenen olacak bunu nasıl örneğidir bağlamı

yok edebilir okuma süreci (kafa) sonlanır ve writi iken boru ucunu kapatır İşlem (python) hala yazmaya çalışır.

anormal bir durum mı ve piton komut bir BrokenPipeError alır - bu yakalar ve komut dosyası hatası işlemek için izin BrokenPipeError yükseltir daha doğrusu Python yorumlayıcısı bir sistem SIGPIPE sinyal alır.

Ve son olarak, son örneğinizde, yalnızca özel durumun göz ardı edildiğini söyleyen bir ileti görüyorsunuz - tamam, bu doğru değil, Python'daki bu open issue ile ilgili görünüyor: Python geliştiricileri, önemli olduğunu düşünüyor. anormal durum hakkında kullanıcıyı uyarır.

Gerçek şu ki, AFAIK python yorumlayıcısı, istisnayı yakalasanız bile, bunu her zaman stderr üzerinde bildirir. Ancak mesajdan kurtulmak için çıkmadan önce stderr'i kapatmanız gerekiyor.

Biraz için komut değiştirdi:

  • catch hata son örnekte olduğu gibi
  • yakalamak ya IOError (Ben Windows64 üzerinde Python34 olsun o) ya da BrokenPipeError (Python 33 FreeBSD üzerinde 9.0) - nedeniyle
  • yakın standart hataya) kırık boru için özel bir stdout'u kapalı (standart hataya mesajı Tamamlandı
  • ekran için bir mesaj gösterir

    import sys 
    
    try: 
        for i in range(4000): 
          print(i, flush=True) 
    except (BrokenPipeError, IOError): 
        print ('BrokenPipeError caught', file = sys.stderr) 
    
    print ('Done', file=sys.stderr) 
    sys.stderr.close() 
    

    ve burada python3.3 pipe.py | head -10 sonucu: mesajın İşte

kurtulmak için çıkmadan önce kullandığım script

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
BrokenPipeError caught 
Done 

Eğer yabancı mesajları istemiyorsanız sadece kullanın:

import sys 

try: 
    for i in range(4000): 
      print(i, flush=True) 
except (BrokenPipeError, IOError): 
    pass 

sys.stderr.close() 
+0

Kesinlikle çok güzel :) Teşekkürler! Ayrıca bir tuple istisnalar koyabildiğini bilmiyordum. Bana da gösterdiğin için teşekkürler. Bu Mac OS X 10.9.4 ve Ubuntu 12.04.2 LTS (tümü 4 kombinasyon) üzerinde 3.3.2 ve 3.4.0 çalışır. BrokenPipeError ve IOError ile kendi başlarına çalışır gibi görünüyor; OSError öğesinin her ikisi de the exception hierarchy. –

4

Python belgelerine göre, bu zaman atılır : Bu kafa yarar stdout okur gerçeği kaynaklanmaktadır

trying to write on a pipe while the other end has been closed

, sonra derhal o kapatır.

Gördüğünüz gibi, her sys.stdout.flush()'u her print()'dan sonra ekleyerek çalışabilirsiniz. Bu bazen Python 3.

çalışmaz unutmayın Böyle awk için alternatif boru almak için edebilirsiniz head -3 aynı sonucu: Bu yardımcı

python3 0to3.py | awk 'NR >= 4 {exit} 1' 

Umut, iyi şanslar!

+0

Bunun için teşekkürler. Maalesef, awk geçici çözümü bir seçenek değildir. Gerçek çıktının kaç satır ürettiğini bilmiyorum. Bir kaç gün boyunca soruyu cevapsız bırakacağım, eğer sakıncası yoksa. Tekrar teşekkürler. –

+0

@ tommy.carstensen Sys.stdout.flush() 'çalışmıyor mu? Ayrıca, 'kafa' ile de kaç satır olacağını bilmek zorunda değilsiniz? – phantom

+0

@ tommy.carstensen İstediğiniz şeyi yapmak mümkün değildir. Programın bu şekilde çalışabilmesi için 'head' işlevini etkinleştirecek bir çözüm bulunmamaktadır. – phantom

1

Eğer yıkıcı aşamasında yükseltilir son durum yayınlanmıştır vardı çıktı görebileceğiniz gibi: o kadar ne olduğunu anlamak için sonuna

Exception BrokenPipeError: BrokenPipeError(32, 'Broken pipe') in <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> ignored 

Basit bir örnek de ignored neden olmasıdır bağlam takip geçerli:

>> class A(): 
...  def __del__(self): 
...   raise Exception("It will be ignored!!!") 
... 
>>> a = A() 
>>> del a 
Exception Exception: Exception('It will be ignored!!!',) in <bound method A.__del__ of <__builtin__.A instance at 0x7ff1d5c06d88>> ignored 
>>> a = A() 
>>> import sys 
>>> sys.stderr.close() 
>>> del a 

nesne durum oluştu ve bir şey b olamayacağını piton bilgilendirecektir çünkü olmasıdır (gözardı açıklamak standart hata çıktı neden olacaktır tahrip ederken tetiklenir Her istisna e imha aşamasında doğru şekilde ele alınmalıdır. Her neyse, bu tür istisnalar önbelleğe alınamaz ve bu yüzden onu oluşturabilecek aramaları kaldırabilir veya stderr'u kapatabilirsiniz.

Soruya geri dönün.Bu istisna, gerçek bir problem değildir (bir de göz ardı edilir), ancak eğer baskı istemiyorsanız, nesnenin imha edileceği veya @SergeBallesta'nın doğru bir şekilde önerildiği gibi stderr kapanacağı zaman çağrılabilen işlevi geçersiz kılmalıdır: fantom çünkü dediğim gibi

import sys 
def _void_f(*args,**kwargs): 
    pass 

for i in range(4000): 
    try: 
     print(i,flush=True) 
    except (BrokenPipeError, IOError): 
     sys.stdout.write = _void_f 
     sys.stdout.flush = _void_f 
     sys.exit() 
+0

Bu bir çözüm değil, 'print' ile flush = True 'ile kullanmak istiyor. – phantom

+0

Yazarken python üzerinde test ettim 3.2 ... şimdi python'a uyarladım 3.4 –

+0

@phantom Bu "print' içinde" flush = True' için bir sürüm ... Bu bir çözüm değil mi? –