Bagaimana cara mendapatkan pesan pengecualian dengan Python dengan benar

97

Apa cara terbaik untuk mendapatkan pesan pengecualian dari komponen pustaka standar dengan Python?

Saya perhatikan bahwa dalam beberapa kasus Anda bisa mendapatkannya melalui messagelapangan seperti ini:

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

tetapi dalam beberapa kasus (misalnya, jika terjadi kesalahan soket) Anda harus melakukan sesuatu seperti ini:

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

Saya bertanya-tanya apakah ada cara standar untuk mencakup sebagian besar situasi ini?

Hati yang beku
sumber
1
Anda menggabungkan dua hal yang berbeda - except Foo as bar:sama dengan except Foo, bar:(kecuali yang pertama lebih baru, dan akan terus berfungsi di 3.x), apakah kesalahan datang dengan messageatribut atau tidak terpisah.
jonrsharpe
1
@F frozenHeart Apakah Anda bertanya apakah mengakses .messagekesalahan adalah cara standar atau tidak?
Anand S Kumar
contoh kedua Anda dengan print(msg)hanyalah jalan pintas untukprint(str(msg))
Salo
@Anand S Kumar Yap. Akankah ini berhasil?
FrozenHeart
4
Saya yakin mengakses messagesudah usang.
Jonathon Reinhart

Jawaban:

94

Jika Anda melihat dokumentasi untuk kesalahan bawaan , Anda akan melihat bahwa sebagian besar Exceptionkelas menetapkan argumen pertama mereka sebagai messageatribut. Tidak semua dari mereka melakukannya.

Khususnya, EnvironmentError(dengan subclass IOErrordan OSError) memiliki argumen pertama errno, kedua strerror. Tidak ada message... yang strerrorsecara kasar analog dengan apa yang biasanya menjadi message.

Secara umum, subkelas dari Exceptiondapat melakukan apapun yang mereka inginkan. Mereka mungkin memiliki atau tidak memiliki messageatribut. Bawaan masa depan Exceptionmungkin tidak memiliki messageatribut. Setiap Exceptionsubclass yang diimpor dari pustaka pihak ketiga atau kode pengguna mungkin tidak memiliki messageatribut.

Saya pikir cara yang tepat untuk menangani ini adalah dengan mengidentifikasi Exceptionsubclass spesifik yang ingin Anda tangkap, dan kemudian hanya menangkap subclass tersebut, bukan semuanya dengan an except Exception, lalu gunakan atribut apa pun yang ditentukan oleh subclass tertentu seperti yang Anda inginkan.

Jika Anda memerlukan printsesuatu, saya pikir mencetak hasil tangkapan Exceptionitu sendiri kemungkinan besar akan melakukan apa yang Anda inginkan, apakah itu memiliki messageatribut atau tidak.

Anda juga dapat memeriksa atribut pesan jika Anda mau, seperti ini, tetapi saya tidak akan menyarankannya karena tampaknya berantakan:

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)
ArtOfWarfare
sumber
Terima kasih atas jawabannya. Apakah ada alasan khusus untuk menggunakan str(ex)selain hanya ex?
FrozenHeart
3
@F frozenHeart - print()secara otomatis memanggil str()Anda. Tidak ada alasan untuk memanggilnya sendiri secara manual, meskipun tidak berbahaya karena memanggil str()string hanya akan mengembalikan string itu sendiri.
ArtOfWarfare
1
@ArtOfWarfare Saya pikir mungkin ada masalah dengan str()pesan jika jenisnya unicode.
kratenko
34

Untuk meningkatkan jawaban yang diberikan oleh @artofwarfare , inilah yang saya anggap sebagai cara yang lebih rapi untuk memeriksa messageatribut dan mencetaknya atau mencetak Exceptionobjek sebagai cadangan.

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

Panggilan ke reprbersifat opsional, tetapi saya merasa perlu dalam beberapa kasus penggunaan.


Perbarui # 1:

Mengikuti komentar @MadPhysicist , berikut adalah bukti mengapa panggilan ke reprmungkin diperlukan. Coba jalankan kode berikut di interpreter Anda:

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

Perbarui # 2:

Berikut adalah demo dengan spesifikasi untuk Python 2.7 dan 3.5: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533

Tosin Mash
sumber
1
getattrmelempar pengecualian jika objek yang diteruskan tidak memiliki atribut yang diminta. Jika Anda ingin melakukan sesuatu seperti itu, saya pikir Anda harus menggunakan argumen ketiga opsional untuk getattr, seperti ini: print getattr(e, 'message', e). Jauh lebih baik dari apa yang saya lakukan. Pilihan lainnya adalah print(e.message if hasattr(e, 'message') else e).
ArtOfWarfare
2
Anda hampir pasti menginginkannya, strbukan repr.
Mad Physicist
2
Dibandingkan str, reprtambahkan saja nama kelas. Alih-alih menggunakan repr, saya mengusulkan untuk menggunakan print('{e.__class__.__name__}: {e}'.format(e=e)). Hasil cetak lebih bersih dan sesuai dengan hasil cetak kenaikan itu sendiri.
kadee
1
Berdasarkan hal di atas, saya menemukan yang paling berguna bagi saya untuk menjadi'{e.__class__.__module__}.{e.__class__.__name__}: {e}'
shadi
1
Terima kasih!! repr(e)untuk saat ini satu-satunya solusi yang membantu saya mencetak setidaknya sejumlah kecil info tentang kesalahan yang saya tangkap dalam beberapa keadaan tertentu. repr(e)menghasilkan KeyError(0,)(yang merupakan kesalahan), sementara str(e)atau e.messagehanya menghasilkan 0atau tidak sama sekali.
FlorianH
0

Saya memiliki masalah yang sama. Saya pikir solusi terbaik adalah menggunakan log.exception, yang secara otomatis akan mencetak jejak tumpukan dan pesan kesalahan, seperti:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')
Bill Z
sumber
1
Apa log? Saya baru saja mencoba import logPython 2.7.13 dan mendapat pesan bahwa tidak ada modul dengan nama itu. Apakah itu sesuatu yang Anda tambahkan melalui pipatau apakah itu ditambahkan dalam versi python yang lebih baru (saya tahu, saya tahu, saya perlu memperbarui ke Python 3 ... Saya akan melakukannya segera setelah CentOS menghentikan pengiriman dengan Python 2 secara default ...)
ArtOfWarfare
6
Dia / Dia mungkin menggunakan modul logging dari python dan kemudian membuat instance logger sebagai variabel log. import logging\ nlog = logging.getLogger(__name__)
Josepas
0

Saya juga punya masalah yang sama. Menggali ini saya menemukan bahwa kelas Exception memiliki argsatribut, yang menangkap argumen yang digunakan untuk membuat pengecualian. Jika Anda mempersempit pengecualian yang akan ditangkap kecuali untuk subset, Anda harus dapat menentukan bagaimana mereka dibangun, dan dengan demikian argumen mana yang berisi pesan tersebut.

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling
pengguna2501097
sumber