Saya sedang menulis modul dan ingin memiliki hierarki eksepsi terpadu untuk pengecualian yang dapat dimunculkan (misalnya mewarisi dari FooError
kelas abstrak untuk semua foo
pengecualian spesifik modul). Ini memungkinkan pengguna modul untuk menangkap pengecualian khusus tersebut dan menanganinya dengan jelas, jika perlu. Tetapi banyak pengecualian yang diangkat dari modul dinaikkan karena beberapa pengecualian lain; misalnya gagal pada beberapa tugas karena OSError pada file.
Yang saya butuhkan adalah untuk "membungkus" pengecualian yang ditangkap sehingga memiliki jenis dan pesan yang berbeda , sehingga informasi tersedia lebih lanjut atas hierarki propagasi oleh apa pun yang menangkap pengecualian. Tapi saya tidak ingin kehilangan jenis, pesan, dan jejak stack yang ada; itu semua informasi yang berguna untuk seseorang yang mencoba men-debug masalah. Penangan pengecualian tingkat atas tidak baik, karena saya mencoba untuk menghias pengecualian sebelum membuat jalannya lebih jauh ke tumpukan propagasi, dan penangan tingkat atas sudah terlambat.
Ini sebagian diselesaikan dengan menurunkan foo
jenis pengecualian spesifik modul saya dari jenis yang ada (misalnya class FooPermissionError(OSError, FooError)
), tetapi itu tidak membuatnya lebih mudah untuk membungkus contoh pengecualian yang ada dalam jenis baru, atau memodifikasi pesan.
PEP 3134 dari Python 3134 " Chains Pengecualian dan Embedded Tracebacks" membahas perubahan yang diterima dalam Python 3.0 untuk objek pengecualian "chaining", untuk menunjukkan bahwa pengecualian baru dimunculkan selama penanganan pengecualian yang ada.
Apa yang saya coba lakukan terkait: Saya membutuhkannya juga bekerja di versi Python sebelumnya, dan saya membutuhkannya bukan untuk chaining, tetapi hanya untuk polimorfisme. Apa cara yang tepat untuk melakukan ini?
sumber
except Exception as e
->raise type(e), type(e)(e.message + custom_message), sys.exc_info()[2]
-> solusi ini dari pertanyaan SO lainnya . Ini tidak cantik tapi fungsional.Jawaban:
Python 3 memperkenalkan chaining pengecualian (seperti yang dijelaskan dalam PEP 3134 ). Ini memungkinkan, saat mengajukan pengecualian, mengutip pengecualian yang ada sebagai "penyebab":
Pengecualian yang tertangkap dengan demikian menjadi bagian dari (adalah "penyebab") pengecualian baru, dan tersedia untuk kode apa pun yang menangkap pengecualian baru.
Dengan menggunakan fitur ini,
__cause__
atribut ditetapkan. Penangan pengecualian bawaan juga tahu bagaimana melaporkan "penyebab" dan "konteks" pengecualian bersama dengan traceback.Dalam Python 2 , tampaknya use case ini tidak memiliki jawaban yang baik (seperti yang dijelaskan oleh Ian Bicking dan Ned Batchelder ). Kekecewaan.
sumber
try: return 2 / 0 except ZeroDivisionError as e: raise ValueError(e)
Anda dapat menggunakan sys.exc_info () untuk mendapatkan traceback, dan meningkatkan pengecualian baru Anda dengan traceback tersebut (seperti yang disebutkan oleh PEP). Jika Anda ingin mempertahankan jenis dan pesan yang lama, Anda dapat melakukannya dengan pengecualian, tetapi itu hanya berguna jika apa pun yang menangkap pengecualian Anda mencarinya.
Sebagai contoh
Tentu saja, ini benar-benar tidak berguna. Jika ya, kita tidak membutuhkan PEP itu. Saya tidak akan merekomendasikan melakukannya.
sumber
sys.exc_info()
, @Devin. Dikatakan, "Menetapkan nilai kembali traceback ke variabel lokal dalam fungsi yang menangani pengecualian akan menyebabkan referensi melingkar." Namun, catatan berikut mengatakan bahwa sejak Python 2.2, siklus dapat dibersihkan, tetapi lebih efisien untuk menghindarinya.Anda bisa membuat jenis pengecualian Anda sendiri yang meluas ke mana pun pengecualian yang Anda tangkap.
Tetapi sebagian besar waktu, saya pikir akan lebih mudah untuk menangkap pengecualian, menanganinya, dan apakah
raise
pengecualian asli (dan menjaga traceback) atauraise NewException()
. Jika saya memanggil kode Anda, dan saya menerima salah satu pengecualian khusus Anda, saya berharap bahwa kode Anda sudah menangani pengecualian apa pun yang harus Anda tangkap. Jadi saya tidak perlu mengaksesnya sendiri.Sunting: Saya menemukan analisis ini tentang cara melempar pengecualian Anda sendiri dan menyimpan pengecualian asli. Tidak ada solusi cantik.
sumber
Saya juga menemukan bahwa berkali-kali saya perlu beberapa "pembungkus" untuk kesalahan yang diajukan.
Ini termasuk dalam lingkup fungsi dan terkadang hanya membungkus beberapa baris di dalam fungsi.
Dibuat pembungkus untuk digunakan
decorator
dancontext manager
:Penerapan
Contoh penggunaan
penghias
saat memanggil
do
metode, jangan khawatirIndexError
, cukupMyError
manajer konteks
di dalam
do2
, dicontext manager
, jikaIndexError
dinaikkan, itu akan dibungkus dan dinaikkanMyError
sumber
Solusi paling tegas untuk kebutuhan Anda adalah:
Dengan cara ini Anda nantinya dapat mencetak pesan Anda dan kesalahan spesifik dilemparkan oleh fungsi unggah
sumber