Latar belakang saya adalah dalam C # dan saya baru saja memulai pemrograman dengan Python. Ketika pengecualian dilemparkan, saya biasanya ingin membungkusnya dalam pengecualian lain yang menambahkan lebih banyak informasi, sambil tetap menunjukkan jejak tumpukan penuh. Ini cukup mudah di C #, tetapi bagaimana cara melakukannya dengan Python?
Misalnya. di C # saya akan melakukan sesuatu seperti ini:
try
{
ProcessFile(filePath);
}
catch (Exception ex)
{
throw new ApplicationException("Failed to process file " + filePath, ex);
}
Dengan Python saya bisa melakukan hal serupa:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file ' + filePath, e)
... tapi ini kehilangan jejak pengecualian batin!
Sunting: Saya ingin melihat pesan pengecualian dan tumpukan jejak serta menghubungkan keduanya. Yaitu, saya ingin melihat dalam output bahwa pengecualian X terjadi di sini dan kemudian pengecualian Y di sana - sama seperti yang saya lakukan di C #. Apakah ini mungkin di Python 2.6? Sepertinya yang terbaik yang bisa saya lakukan sejauh ini (berdasarkan jawaban Glenn Maynard) adalah:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file' + filePath, e), None, sys.exc_info()[2]
Ini termasuk pesan dan traceback, tetapi tidak menunjukkan pengecualian mana yang terjadi di traceback.
Jawaban:
Python 2
Itu mudah; melewati traceback sebagai argumen ketiga untuk diajukan.
Selalu lakukan ini saat menangkap satu pengecualian dan memunculkan kembali yang lain.
sumber
raise MyException(str(e)), ...
, dll.raise E() from tb
dan.with_traceback(...)
raise
adalah untuk meneruskan ke pengecualian (jika argumen pertama adalah kelas pengecualian dan bukan sebuah instance). Jadi jika Anda ingin pengecualian swap, bukannya melakukanraise MyException(str(e)), None, sys.exc_info()[2]
, lebih baik untuk menggunakan ini:raise MyException, e.args, sys.exc_info()[2]
.from future.utils import raise_
danraise_(ValueError, None, sys.exc_info()[2])
.Python 3
Dalam python 3 Anda dapat melakukan hal berikut:
Ini akan menghasilkan sesuatu seperti ini:
sumber
raise ... from ...
memang cara yang tepat untuk melakukan ini di Python 3. Ini membutuhkan lebih banyak upvotes.Nakedible
Saya pikir itu karena sayangnya kebanyakan orang masih tidak menggunakan Python 3.future
paket untuk mencapai ini: python-future.org/compatible_idioms.html#raising-exceptions Misalnyafrom future.utils import raise_
danraise_(ValueError, None, sys.exc_info()[2])
.Python 3 memiliki
raise
...from
klausa untuk pengecualian rantai. Jawaban Glenn bagus untuk Python 2.7, tetapi hanya menggunakan traceback pengecualian asli dan membuang pesan kesalahan dan detail lainnya. Berikut adalah beberapa contoh di Python 2.7 yang menambahkan informasi konteks dari lingkup saat ini ke pesan kesalahan pengecualian asli, tetapi tetap detail lainnya tetap utuh.Jenis Pengecualian yang Dikenal
Rasa
raise
pernyataan itu mengambil tipe pengecualian sebagai ekspresi pertama, argumen konstruktor kelas pengecualian dalam tuple sebagai ekspresi kedua, dan traceback sebagai ekspresi ketiga. Jika Anda menjalankan lebih awal dari Python 2.2, lihat peringatan disys.exc_info()
.Semua Jenis Pengecualian
Berikut ini contoh lain yang lebih umum jika Anda tidak tahu pengecualian apa yang harus ditangkap oleh kode Anda. The downside adalah bahwa ia kehilangan tipe pengecualian dan hanya menimbulkan RuntimeError. Anda harus mengimpor
traceback
modul.Ubah Pesan
Berikut opsi lain jika jenis pengecualian akan memungkinkan Anda menambahkan konteks. Anda dapat mengubah pesan pengecualian dan kemudian mengembalikannya.
Itu menghasilkan jejak tumpukan berikut:
Anda dapat melihat bahwa itu menunjukkan baris di mana
check_output()
dipanggil, tetapi pesan pengecualian sekarang termasuk baris perintah.sumber
ex.strerror
datangnya? Saya tidak dapat menemukan klik yang relevan untuk itu di Python docs. Bukankah seharusnya begitustr(ex)
?IOError
berasal dariEnvironmentError
, @hheimbuerger, yang menyediakan atributerrorno
danstrerror
.Error
, misalnya ValueError,RuntimeError
dengan menangkapException
? Jika saya mereproduksi jawaban Anda untuk kasus ini, stacktrace hilang.Dengan Python 3.x :
atau sederhana
yang akan menyebar
MyException
tetapi mencetak kedua pengecualian jika tidak akan ditangani.Dengan Python 2.x :
Anda dapat mencegah pencetakan kedua pengecualian dengan mematikan
__context__
atribut. Di sini saya menulis manajer konteks menggunakan itu untuk menangkap dan mengubah pengecualian Anda dengan cepat: (lihat http://docs.python.org/3.1/library/stdtypes.html untuk penjelasan bagaimana mereka bekerja)sumber
e.__traceback__
atribut!Saya tidak berpikir Anda bisa melakukan ini di Python 2.x, tetapi sesuatu yang mirip dengan fungsi ini adalah bagian dari Python 3. Dari PEP 3134 :
Perbandingan dengan C #:
Perhatikan juga bahwa Java, Ruby dan Perl 5 juga tidak mendukung jenis hal ini. Mengutip lagi:
sumber
Untuk kompatibilitas maksimum antara Python 2 dan 3, Anda bisa menggunakannya
raise_from
disix
perpustakaan. https://six.readthedocs.io/#six.raise_from . Inilah contoh Anda (sedikit dimodifikasi untuk kejelasan):sumber
Anda bisa menggunakan kelas CausedException saya untuk membuat pengecualian di Python 2.x (dan bahkan dalam Python 3 dapat berguna jika Anda ingin memberikan lebih dari satu pengecualian yang tertangkap sebagai penyebab pengecualian yang baru diangkat). Mungkin itu bisa membantu Anda.
sumber
Mungkin Anda bisa mengambil informasi yang relevan dan meneruskannya? Saya sedang memikirkan sesuatu seperti:
sumber
Asumsi:
raise ... from
solusi lihat Python 3 murni )Anda dapat menggunakan solusi sederhana dari dokumen https://docs.python.org/3/tutorial/errors.html#raising-exceptions :
Hasil:
Sepertinya bagian kunci adalah kata kunci 'kenaikan' yang disederhanakan yang berdiri sendiri. Itu akan menaikkan kembali Exception di blok kecuali.
sumber