Python'da doğru şekilde istisna mesajı nasıl alınır


97

Python'daki standart kitaplık bileşenlerinden istisna mesajlarını almanın en iyi yolu nedir?

Bazı durumlarda bunu aşağıdaki messagegibi alan yoluyla alabileceğinizi fark ettim :

try:
  pass
except Exception as ex:
  print(ex.message)

ancak bazı durumlarda (örneğin, soket hataları olması durumunda) şuna benzer bir şey yapmanız gerekir:

try:
  pass
except socket.error as ex:
  print(ex)

Bu durumların çoğunu ele almanın standart bir yolu var mı?


1
İki farklı şeyi karıştırıyorsunuz - hatanın bir öznitelikle gelip gelmemesine bakılmaksızın except Foo as bar:aynıdır except Foo, bar:(eski daha yeni ve 3.x'te çalışmaya devam edecek) ile aynıdır message.
jonrsharpe

1
@FrozenHeart .messageBir hata için erişimin standart bir yol olup olmadığını mı soruyorsunuz ?
Anand S Kumar

ile ikinci örneğiniz print(msg)sadece kısayolprint(str(msg))
Salo

@Anand S Kumar Yep. Her durumda çalışacak mı?
FrozenHeart

4
messageErişmenin kullanımdan kaldırıldığına inanıyorum .
Jonathan Reinhart

Yanıtlar:


94

Yerleşik hataların belgelerine bakarsanız, çoğu Exceptionsınıfın ilk bağımsız değişkenini bir messageöznitelik olarak atadığını görürsünüz . Yine de hepsi yapmıyor.

Özellikle, EnvironmentError(alt sınıflarla IOErrorve OSError) birinci argümanına sahiptir errno, ikincisi strerror. Yok message... strerrornormalde a olacağına kabaca benzeşmez message.

Daha genel olarak, alt sınıfları Exceptionistediklerini yapabilir. Bir messageöznitelikleri olabilir veya olmayabilir . Gelecekteki yerleşik e-postaların Exceptionbir messageözniteliği olmayabilir . ExceptionÜçüncü taraf kitaplıklarından veya kullanıcı kodundan içe aktarılan herhangi bir alt sınıfın bir messageözniteliği olmayabilir .

Bence bunu ele almanın doğru yolu, Exceptionyakalamak istediğiniz belirli alt sınıfları tanımlamak ve sonra bir ile her şey yerine sadece bunları yakalamak ve ardından except Exceptionbelirli alt sınıfın istediğiniz şekilde tanımladığı nitelikleri kullanmaktır.

Bir printşey yapmanız gerekiyorsa , bence yakalanan Exceptionşeyi basmanın, bir messageniteliği olsun ya da olmasın , istediğiniz şeyi yapma olasılığı yüksektir .

İsterseniz mesaj özniteliğini de kontrol edebilirsiniz, bunun gibi, ancak dağınık göründüğü için gerçekten önermem:

try:
    pass
except Exception as e:
    # Just print(e) is cleaner and more likely what you want,
    # but if you insist on printing message specifically whenever possible...
    if hasattr(e, 'message'):
        print(e.message)
    else:
        print(e)

Cevap için teşekkürler. str(ex)Sadece kullanmak yerine kullanmak için özel bir sebep var mı ex?
FrozenHeart

3
@FrozenHeart - sizi print()otomatik olarak arar str(). Kendiniz manuel olarak adlandırmanız için hiçbir neden yoktur, ancak zararsızdır, çünkü str()bir dizeyi çağırmak dizenin kendisini döndürür.
ArtOfWarfare

1
@ArtOfWarfare str()Mesaj türünde bir sorun olabileceğini düşünüyorum unicode.
kratenko

35

@Artofwarfare tarafından sağlanan yanıtı iyileştirmek için , burada messageözniteliği kontrol etmenin ve onu yazdırmanın veya Exceptionnesneyi bir yedek olarak yazdırmanın daha düzgün bir yolunu buluyorum .

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

Çağrısı repristeğe bağlıdır, ancak bazı kullanım durumlarında gerekli buluyorum.


1 numaralı güncelleme:

@MadPhysicist tarafından yapılan yorumun ardından, çağrının neden reprgerekli olabileceğinin bir kanıtı burada . Yorumlayıcınızda aşağıdaki kodu çalıştırmayı deneyin:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

2 numaralı güncelleme:

İşte Python 2.7 ve 3.5'in özelliklerini içeren bir demo: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533


1
getattriletilen nesne istenen özniteliğe sahip değilse bir istisna atar. Eğer böyle bir şey yapmak istiyorsa, ben sizin için isteğe bağlı üçüncü argüman kullanmak gerektiğini düşünüyorum getattrbu gibi: print getattr(e, 'message', e). Yaptığımdan tartışmalı bir şekilde daha iyi. Başka bir seçenek de olabilir print(e.message if hasattr(e, 'message') else e).
ArtOfWarfare

2
Bunun stryerine neredeyse kesinlikle isteyecektin repr.
Mad Fizikçi

2
İle karşılaştırıldığında str, reprsadece sınıf adını ekler. Kullanmak yerine kullanmayı repröneririm print('{e.__class__.__name__}: {e}'.format(e=e)). Baskı çıktısı daha temizdir ve kendini yükseltme çıktısına yapışır.
kadee

1
Yukarıdaki dayanarak, olmamı için en yararlı bulundu'{e.__class__.__module__}.{e.__class__.__name__}: {e}'
vasiliy

1
Teşekkürler!! repr(e)Şimdilik, belirli bir durumda yakaladığım bir hatayla ilgili en azından minimum miktarda bilgi yazdırmama yardımcı olan tek çözümdü. repr(e)verimleri KeyError(0,)ise (hatanın ne olduğu), str(e)veya e.messagesadece vermiştir 0sırasıyla hiç ya da hiç.
FlorianH

0

Ben de aynı sorunu yaşadım. Bence en iyi çözüm, aşağıdaki gibi yığın izleme ve hata mesajlarını otomatik olarak yazdıran log.exception kullanmaktır:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

1
Nedir log? Az import logönce Python 2.7.13'ü denedim ve bu isimde modül olmadığına dair bir mesaj aldım. Bu, sizin eklediğiniz bir şey mi pipyoksa daha yeni bir python sürümüne mi eklendi (biliyorum, biliyorum, Python 3'e güncellemem gerekiyor ... Bunu CentOS varsayılan olarak Python 2 ile gönderimi durdurur kesmez yapacağım ...)
ArtOfWarfare

6
Muhtemelen python'daki loglama modülünü kullanıyor ve ardından bir logger'ı bir log değişkeni olarak başlatıyor. import logging\ nlog = logging.getLogger(__name__)
Josepas

0

Ben de aynı sorunu yaşadım. Bunu derinlemesine inceleyerek, Exception sınıfının, argsistisnayı oluşturmak için kullanılan argümanları yakalayan bir niteliği olduğunu buldum . Bir alt kümeye yakalanacak istisnaları daraltırsanız, bunların nasıl inşa edildiğini ve böylece hangi argümanın mesajı içerdiğini belirleyebilmelisiniz.

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling
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.