Jika Anda ingin mengetahui lebih banyak tentang ini daripada jawabannya, google menelan pengecualian. Anda dapat melakukan segala macam hal yang menarik dan tidak boleh dilakukan bersama mereka. Bau kode adalah satu lagi.
Tony Hopkinson
Jawaban:
89
Hampir selalu lebih baik untuk menentukan jenis pengecualian eksplisit. Jika Anda menggunakan except:klausa telanjang , Anda mungkin akan menemukan pengecualian selain yang Anda harapkan untuk ditangkap - ini dapat menyembunyikan bug atau mempersulit program debug ketika mereka tidak melakukan apa yang Anda harapkan.
Misalnya, jika Anda menyisipkan baris ke dalam database, Anda mungkin ingin menangkap pengecualian yang menunjukkan bahwa baris tersebut sudah ada, sehingga Anda bisa melakukan pembaruan.
Jika Anda menentukan telanjang except:, Anda juga akan menemukan kesalahan soket yang menunjukkan bahwa server database telah jatuh. Sebaiknya hanya menangkap pengecualian yang Anda tahu cara menanganinya - seringkali lebih baik jika program gagal pada titik pengecualian daripada melanjutkan tetapi berperilaku aneh dan tidak terduga.
Satu kasus di mana Anda mungkin ingin menggunakan telanjang except:adalah di tingkat atas program yang Anda butuhkan untuk selalu berjalan, seperti server jaringan. Tapi kemudian, Anda harus sangat berhati-hati untuk mencatat pengecualian, jika tidak, tidak mungkin mengetahui apa yang salah. Pada dasarnya, hanya boleh ada paling banyak satu tempat dalam program yang melakukan ini.
Konsekuensi dari semua ini adalah bahwa kode Anda tidak boleh melakukannya raise Exception('some message')karena memaksa kode klien untuk digunakan except:(atau except Exception:yang hampir sama buruknya). Anda harus menentukan pengecualian khusus untuk masalah yang ingin Anda beri sinyal (mungkin mewarisi dari beberapa subkelas pengecualian bawaan seperti ValueErroratau TypeError). Atau Anda harus meningkatkan pengecualian bawaan tertentu. Ini memungkinkan pengguna kode Anda untuk berhati-hati dalam menangkap hanya pengecualian yang ingin mereka tangani.
+1 Sangat benar. Bahkan lebih menyenangkan dengan contoh: except:juga menangkap (di antara banyak hal lainnya) NameErrordan AttributeError, jadi jika Anda salah mengeja sesuatu di tryblok (misalnya fungsi "sisipkan" Anda sebenarnya dipanggil insert_onekarena seseorang tidak menghargai konsistensi sebanyak yang seharusnya), itu selalu diam-diam mencoba update().
1
Jadi bagaimana dengan saat Anda perlu memastikan pengecualian tidak dilemparkan di atas situs panggilan saat ini? Yaitu - Saya telah menangkap semua pengecualian spesifik yang dapat saya perkirakan akan terlempar, sekarang saya perlu menambahkan bahwa "jika hal yang belum saya pikirkan ini terlempar, saya perlu mencatatnya sebelum membunuh konteks eksekusi yang berjalan" (seperti main())?
Adam Parkin
Itulah jenis situasi yang saya bicarakan di paragraf awal 'Satu kasus ...'. Terkadang memang diperlukan, tetapi program apa pun harus benar-benar hanya memiliki satu tempat yang melakukan itu. Dan Anda harus berhati-hati agar jelas di log apa yang terjadi, jika tidak Anda akan memiliki waktu frustasi mencoba mencari tahu mengapa program Anda tidak menangani acara / permintaan / apapun dengan benar.
babbageclunk
3
@ Delnan: Lebih buruk dari itu. except Exception:akan menangkap NameErrordan AttributeErrorjuga. Apa yang membuat telanjang except:begitu buruk adalah bahwa ia menangkap hal-hal yang tidak ada urusannya ditangkap, misalnya SystemExit(diangkat saat Anda menelepon exitatau sys.exit, dan sekarang Anda telah mencegah jalan keluar yang diinginkan) dan KeyboardInterrupt(sekali lagi, jika pengguna memukul Ctrl-C, Anda mungkin tidak ingin untuk tetap berlari hanya untuk membencinya). Hanya yang terakhir yang masuk akal untuk ditangkap, dan itu harus ditangkap secara eksplisit. Setidaknya except Exception:biarkan keduanya menyebar secara normal.
ShadowRanger
38
Anda tidak boleh mengabaikan nasihat yang diberikan penerjemah kepada Anda.
A bare exception: clause akan menangkap pengecualian SystemExit dan KeyboardInterrupt, membuatnya lebih sulit untuk mengganggu program dengan Control-C, dan dapat menyamarkan masalah lain. Jika Anda ingin menangkap semua pengecualian yang menandakan kesalahan program, gunakan kecuali Exception: (telanjang kecuali sama dengan kecuali BaseException :).
Aturan praktis yang baik adalah membatasi penggunaan klausa 'kecuali' untuk dua kasus:
Jika penangan pengecualian akan mencetak atau mencatat traceback; setidaknya pengguna akan menyadari bahwa telah terjadi kesalahan. Jika kode perlu melakukan beberapa pekerjaan pembersihan, tetapi kemudian biarkan pengecualian menyebar ke atas dengan kenaikan. coba ... akhirnya bisa menjadi cara yang lebih baik untuk menangani kasus ini.
Inti dari pengecualian adalah menangani masalah sedekat mungkin dengan penyebabnya.
Jadi, Anda menyimpan kode yang dapat dalam keadaan luar biasa dapat memicu masalah dan resolusi "bersebelahan" satu sama lain.
Masalahnya adalah Anda tidak bisa mengetahui semua pengecualian yang bisa dilemparkan oleh sepotong kode. Yang dapat Anda ketahui adalah bahwa jika itu adalah pengecualian untuk mengatakan file tidak ditemukan, maka Anda bisa menjebaknya dan meminta pengguna untuk mendapatkan yang tidak atau membatalkan fungsi.
Jika Anda mencoba menangkapnya, maka tidak peduli masalah apa yang ada dalam rutin file Anda (hanya baca, izin, UAC, bukan pdf, dll), setiap orang akan masuk ke file Anda tidak ditemukan, dan pengguna Anda berteriak "tapi itu ada, kode ini omong kosong"
Sekarang ada beberapa situasi di mana Anda mungkin menangkap semuanya, tetapi mereka harus dipilih secara sadar.
Mereka menangkap, membatalkan beberapa tindakan lokal (seperti membuat atau mengunci sumber daya, (membuka file pada disk untuk menulis misalnya), lalu Anda melempar pengecualian lagi, untuk ditangani di tingkat yang lebih tinggi)
Anda yang lain adalah Anda tidak peduli mengapa itu salah. Mencetak misalnya. Anda mungkin memiliki pemahaman bahwa, untuk mengatakan Ada beberapa masalah dengan printer Anda, tolong selesaikan, dan jangan mematikan aplikasi karena itu. Ona sama sia-sia jika kode Anda mengeksekusi serangkaian tugas terpisah menggunakan semacam jadwal, Anda tidak ingin semuanya mati, karena salah satu tugas gagal.
Catatan Jika Anda melakukan hal di atas, saya tidak dapat merekomendasikan semacam pencatatan pengecualian, misalnya coba tangkap log akhir, cukup tinggi.
Saya akan mengatakan ini tentang keseimbangan. Anda harus menangkap pengecualian cukup awal untuk dapat memulihkannya dan cukup terlambat untuk mengetahui ke mana harus pergi bersamanya. Itulah mengapa penanganan pengecualian Java menyebabkan malapetaka seperti itu, karena Anda harus membungkus ulang pengecualian di setiap langkah dan Anda kehilangan informasi.
bukit pasir
2
+1 untuk "Anda tidak peduli mengapa itu salah." Saya menggunakannya di beberapa tempat di sekitar satu baris kode tempat saya mengurai tanggal / waktu dari URL. Pustaka penguraian tanggal / waktu pihak ketiga tidak mencantumkan semua pengecualian yang dapat dilontarkannya (saya telah menemukan OverflowError dan TypeError selain ValueError standar, tetapi mungkin ada lebih banyak), dan bagaimanapun saya benar-benar tidak peduli mengapa pengecualian dilempar, saya hanya ingin memberikan pesan kesalahan yang masuk akal kembali kepada pengguna yang mengatakan bahwa ada yang salah dengan tanggal / waktu.
Michael Rodby
3
Anda juga akan menangkap misalnya Control-C dengan itu, jadi jangan lakukan kecuali Anda "membuang" lagi. Namun, dalam hal ini Anda sebaiknya menggunakan "akhirnya".
akan menggunakan except Exception:menghindari jenis di atas yang tidak ingin kita tangkap?
HorseloverFat
except Exceptionbaik-baik saja.
Ulrich Eckhardt
4
@HorseloverFat: except Exceptionmenangkap SyntaxErrordan MemoryErrorkarena itu adalah kelas dasar mereka. KeyboardInterrupt, SystemExit(dimunculkan oleh sys.exit()) tidak tertangkap (mereka adalah subclass BaseException langsung)
jfs
terdengar seperti itu tidak ideal - lebih baik untuk menentukan dengan lebih tepat.
HorseloverFat
3
Berikut adalah tempat-tempat yang saya gunakan kecuali tanpa tipe
prototipe cepat dan kotor
Itulah penggunaan utama dalam kode saya untuk pengecualian yang tidak dicentang
fungsi main () tingkat atas, di mana saya mencatat setiap pengecualian yang tidak tertangkap
Saya selalu menambahkan ini, sehingga kode produksi tidak menumpahkan stacktraces
di antara lapisan aplikasi
Saya punya dua cara untuk melakukannya:
Cara pertama untuk melakukannya: ketika lapisan tingkat yang lebih tinggi memanggil fungsi tingkat yang lebih rendah, itu membungkus panggilan dalam pengecualian yang diketik untuk menangani pengecualian tingkat bawah "atas". Tetapi saya menambahkan pernyataan pengecualian umum, untuk mendeteksi pengecualian tingkat bawah yang tidak tertangani di fungsi tingkat yang lebih rendah.
Saya lebih suka dengan cara ini, saya merasa lebih mudah untuk mendeteksi pengecualian mana yang seharusnya ditangkap dengan tepat: saya "melihat" masalah dengan lebih baik ketika pengecualian tingkat yang lebih rendah dicatat oleh tingkat yang lebih tinggi
Cara kedua untuk melakukannya: setiap fungsi tingkat atas dari lapisan tingkat yang lebih rendah memiliki kodenya yang dibungkus secara umum kecuali, untuk itu menangkap semua pengecualian yang tidak tertangani pada lapisan tertentu itu.
Beberapa rekan kerja lebih suka cara ini, karena cara ini mempertahankan pengecualian tingkat yang lebih rendah di fungsi tingkat yang lebih rendah, di mana mereka "termasuk".
Jawaban:
Hampir selalu lebih baik untuk menentukan jenis pengecualian eksplisit. Jika Anda menggunakan
except:
klausa telanjang , Anda mungkin akan menemukan pengecualian selain yang Anda harapkan untuk ditangkap - ini dapat menyembunyikan bug atau mempersulit program debug ketika mereka tidak melakukan apa yang Anda harapkan.Misalnya, jika Anda menyisipkan baris ke dalam database, Anda mungkin ingin menangkap pengecualian yang menunjukkan bahwa baris tersebut sudah ada, sehingga Anda bisa melakukan pembaruan.
Jika Anda menentukan telanjang
except:
, Anda juga akan menemukan kesalahan soket yang menunjukkan bahwa server database telah jatuh. Sebaiknya hanya menangkap pengecualian yang Anda tahu cara menanganinya - seringkali lebih baik jika program gagal pada titik pengecualian daripada melanjutkan tetapi berperilaku aneh dan tidak terduga.Satu kasus di mana Anda mungkin ingin menggunakan telanjang
except:
adalah di tingkat atas program yang Anda butuhkan untuk selalu berjalan, seperti server jaringan. Tapi kemudian, Anda harus sangat berhati-hati untuk mencatat pengecualian, jika tidak, tidak mungkin mengetahui apa yang salah. Pada dasarnya, hanya boleh ada paling banyak satu tempat dalam program yang melakukan ini.Konsekuensi dari semua ini adalah bahwa kode Anda tidak boleh melakukannya
raise Exception('some message')
karena memaksa kode klien untuk digunakanexcept:
(atauexcept Exception:
yang hampir sama buruknya). Anda harus menentukan pengecualian khusus untuk masalah yang ingin Anda beri sinyal (mungkin mewarisi dari beberapa subkelas pengecualian bawaan sepertiValueError
atauTypeError
). Atau Anda harus meningkatkan pengecualian bawaan tertentu. Ini memungkinkan pengguna kode Anda untuk berhati-hati dalam menangkap hanya pengecualian yang ingin mereka tangani.sumber
except:
juga menangkap (di antara banyak hal lainnya)NameError
danAttributeError
, jadi jika Anda salah mengeja sesuatu ditry
blok (misalnya fungsi "sisipkan" Anda sebenarnya dipanggilinsert_one
karena seseorang tidak menghargai konsistensi sebanyak yang seharusnya), itu selalu diam-diam mencobaupdate()
.main()
)?except Exception:
akan menangkapNameError
danAttributeError
juga. Apa yang membuat telanjangexcept:
begitu buruk adalah bahwa ia menangkap hal-hal yang tidak ada urusannya ditangkap, misalnyaSystemExit
(diangkat saat Anda meneleponexit
atausys.exit
, dan sekarang Anda telah mencegah jalan keluar yang diinginkan) danKeyboardInterrupt
(sekali lagi, jika pengguna memukulCtrl-C
, Anda mungkin tidak ingin untuk tetap berlari hanya untuk membencinya). Hanya yang terakhir yang masuk akal untuk ditangkap, dan itu harus ditangkap secara eksplisit. Setidaknyaexcept Exception:
biarkan keduanya menyebar secara normal.Anda tidak boleh mengabaikan nasihat yang diberikan penerjemah kepada Anda.
Dari Panduan Gaya PEP-8 untuk Python:
sumber
except BaseException
tidak memiliki arti yang sama sepertiexcept
: di Python 2; dengan Python 2 Anda bisa meningkatkan kelas gaya lama sebagai pengecualian, yang tidak mewarisiBaseException
.Ini tidak spesifik untuk Python.
Inti dari pengecualian adalah menangani masalah sedekat mungkin dengan penyebabnya.
Jadi, Anda menyimpan kode yang dapat dalam keadaan luar biasa dapat memicu masalah dan resolusi "bersebelahan" satu sama lain.
Masalahnya adalah Anda tidak bisa mengetahui semua pengecualian yang bisa dilemparkan oleh sepotong kode. Yang dapat Anda ketahui adalah bahwa jika itu adalah pengecualian untuk mengatakan file tidak ditemukan, maka Anda bisa menjebaknya dan meminta pengguna untuk mendapatkan yang tidak atau membatalkan fungsi.
Jika Anda mencoba menangkapnya, maka tidak peduli masalah apa yang ada dalam rutin file Anda (hanya baca, izin, UAC, bukan pdf, dll), setiap orang akan masuk ke file Anda tidak ditemukan, dan pengguna Anda berteriak "tapi itu ada, kode ini omong kosong"
Sekarang ada beberapa situasi di mana Anda mungkin menangkap semuanya, tetapi mereka harus dipilih secara sadar.
Mereka menangkap, membatalkan beberapa tindakan lokal (seperti membuat atau mengunci sumber daya, (membuka file pada disk untuk menulis misalnya), lalu Anda melempar pengecualian lagi, untuk ditangani di tingkat yang lebih tinggi)
Anda yang lain adalah Anda tidak peduli mengapa itu salah. Mencetak misalnya. Anda mungkin memiliki pemahaman bahwa, untuk mengatakan Ada beberapa masalah dengan printer Anda, tolong selesaikan, dan jangan mematikan aplikasi karena itu. Ona sama sia-sia jika kode Anda mengeksekusi serangkaian tugas terpisah menggunakan semacam jadwal, Anda tidak ingin semuanya mati, karena salah satu tugas gagal.
Catatan Jika Anda melakukan hal di atas, saya tidak dapat merekomendasikan semacam pencatatan pengecualian, misalnya coba tangkap log akhir, cukup tinggi.
sumber
Anda juga akan menangkap misalnya Control-C dengan itu, jadi jangan lakukan kecuali Anda "membuang" lagi. Namun, dalam hal ini Anda sebaiknya menggunakan "akhirnya".
sumber
Selalu menentukan jenis pengecualian, ada banyak jenis Anda tidak ingin menangkap, seperti
SyntaxError
,KeyboardInterrupt
,MemoryError
dllsumber
except Exception:
menghindari jenis di atas yang tidak ingin kita tangkap?except Exception
baik-baik saja.except Exception
menangkapSyntaxError
danMemoryError
karena itu adalah kelas dasar mereka.KeyboardInterrupt
,SystemExit
(dimunculkan olehsys.exit()
) tidak tertangkap (mereka adalah subclass BaseException langsung)Berikut adalah tempat-tempat yang saya gunakan kecuali tanpa tipe
Itulah penggunaan utama dalam kode saya untuk pengecualian yang tidak dicentang
Saya selalu menambahkan ini, sehingga kode produksi tidak menumpahkan stacktraces
Saya punya dua cara untuk melakukannya:
Saya lebih suka dengan cara ini, saya merasa lebih mudah untuk mendeteksi pengecualian mana yang seharusnya ditangkap dengan tepat: saya "melihat" masalah dengan lebih baik ketika pengecualian tingkat yang lebih rendah dicatat oleh tingkat yang lebih tinggi
Beberapa rekan kerja lebih suka cara ini, karena cara ini mempertahankan pengecualian tingkat yang lebih rendah di fungsi tingkat yang lebih rendah, di mana mereka "termasuk".
sumber
Coba ini:
Saya mendapat jawaban dari tautan ini, jika ada orang lain yang mengalami masalah ini Periksa
sumber