Saya tahu bahwa jika saya ingin memunculkan kembali pengecualian, saya menggunakan sederhana raise
tanpa argumen di except
blok masing-masing . Tapi diberi ekspresi bersarang seperti
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e # I'd like to raise the SomeError as if plan_B()
# didn't raise the AlsoFailsError
bagaimana cara menaikkan kembali SomeError
tanpa merusak jejak tumpukan? raise
sendiri akan dalam hal ini mengangkat kembali yang lebih baru AlsoFailsError
. Atau bagaimana saya dapat mengubah kode saya untuk menghindari masalah ini?
plan_B
fungsi lain yang mengembalikanTrue
kesuksesan, danFalse
pengecualian? Makaexcept
blok luar mungkin sajaif not try_plan_B(): raise
arg
dan saya akan mencoba meneleponarg.plan_B()
yang mungkin menimbulkanAttributeError
karenaarg
tidak menyediakan rencana Bplan_B
untuk meningkatkan pengecualianJawaban:
Pada Python 3, traceback disimpan dalam pengecualian, jadi simple
raise e
akan melakukan (sebagian besar) hal yang benar:Traceback yang dihasilkan akan menyertakan pemberitahuan tambahan yang
SomeError
terjadi saat menanganiAlsoFailsError
(karenaraise e
berada di dalamexcept AlsoFailsError
). Ini menyesatkan karena yang sebenarnya terjadi adalah sebaliknya - kami bertemuAlsoFailsError
, dan menanganinya, sambil mencoba memulihkanSomeError
. Untuk mendapatkan traceback yang tidak termasukAlsoFailsError
, gantiraise e
denganraise e from None
.Di Python 2 Anda akan menyimpan jenis pengecualian, nilai, dan pelacakan balik di variabel lokal dan menggunakan bentuk tiga argumen dari
raise
:sumber
raise self.exc_info[1], None, self.exc_info[2]
setelahself.exc_info = sys.exc_info()
- menempatkan[1]
ke posisi pertama karena beberapa alasanraise t, None, tb
akan kehilangan nilai pengecualian dan akan memaksaraise
untuk membuat instance ulang dari jenisnya, memberi Anda nilai pengecualian yang kurang spesifik (atau salah). Misalnya, jika pengecualian yang dimunculkan adalahKeyError("some-key")
, itu hanya akan memunculkan kembaliKeyError()
dan menghilangkan kunci yang benar-benar hilang dari traceback.raise v.with_traceback(tb)
. (Komentar Anda bahkan mengatakan sebanyak itu, kecuali itu mengusulkan untuk mengembalikan nilai.)sys.exc_info()
dalam variabel lokal masuk akal sebelum Python 2.0 (dirilis 13 tahun yang lalu), tetapi berbatasan dengan konyol hari ini. Python modern hampir tidak berguna tanpa cycle collector, karena setiap pustaka Python non-sepele membuat siklus tanpa jeda dan bergantung pada pembersihan yang benar.Bahkan jika solusi yang diterima benar, ada baiknya untuk menunjuk ke perpustakaan Six yang memiliki solusi Python 2 + 3, menggunakan
six.reraise
.Jadi, Anda bisa menulis:
sumber
six.raise_from
jika Anda ingin memasukkan informasi yangplan_B()
juga gagal.six.raise_from
Anda membuat pengecualian baru yang ditautkan ke yang sebelumnya, Anda tidak perlu menaikkan kembali , jadi penelusuran kembali berbeda.reraise
mendapatkan kesan hanyasomething()
melemparkanSomeError
, jikaraise_from
Anda juga tahu bahwa ini menyebabkanplan_B()
untuk dieksekusi tetapi membuangAlsoFailsError
. Jadi itu tergantung pada usecase. Saya pikirraise_from
akan membuat debugging lebih mudahSesuai saran Drew McGowen , tetapi menangani kasus umum (di mana nilai kembali
s
ada), berikut adalah alternatif jawaban pengguna4815162342 :sumber
raise from
, jadi pelacakan tumpukan juga akan membiarkan saya melihat rencana B gagal. Yang bisa ditiru dengan Python 2 .Python 3.5+ tetap melampirkan informasi pelacakan ke kesalahan, jadi tidak perlu lagi menyimpannya secara terpisah.
sumber
except
. Tapi Anda benar, ketika saya menggantierr = e
dengan, katakanlahraise AttributeError
, Anda mendapatkanSyntaxError
jejak tumpukan terlebih dahulu , diikuti oleh aDuring handling of the above exception, another exception occurred:
danAttributeError
jejak tumpukan. Sebaiknya Anda tahu, meskipun sayangnya tidak dapat mengandalkan 3.5+ yang diinstal. PS: ff verstehen nicht-Deutsche vermutlich nicht;)