"Saya tidak tahu apakah itu karena ketidaktahuan, tapi saya tidak suka pemrograman seperti itu, karena menggunakan pengecualian untuk melakukan kontrol aliran."
Di dunia Python, menggunakan pengecualian untuk kontrol aliran adalah umum dan normal.
Bahkan pengembang inti Python menggunakan pengecualian untuk flow-control dan gaya itu sangat dimasukkan ke dalam bahasa (yaitu protokol iterator menggunakan StopIteration untuk memberi sinyal penghentian loop).
Selain itu, coba-kecuali-gaya digunakan untuk mencegah kondisi ras yang melekat dalam beberapa konstruksi "look-before-you-leap" . Misalnya, pengujian os.path.exists menghasilkan informasi yang mungkin kedaluwarsa pada saat Anda menggunakannya. Demikian juga, Queue.full mengembalikan informasi yang mungkin basi. Gaya coba-kecuali-yang lain akan menghasilkan kode yang lebih andal dalam kasus ini.
"Ini pemahaman saya bahwa pengecualian bukan kesalahan, mereka hanya boleh digunakan untuk kondisi luar biasa"
Dalam beberapa bahasa lain, aturan itu mencerminkan norma budaya mereka sebagaimana tercermin dalam perpustakaan mereka. "Aturan" juga sebagian didasarkan pada pertimbangan kinerja untuk bahasa tersebut.
Norma budaya Python agak berbeda. Dalam banyak kasus, Anda harus menggunakan pengecualian untuk aliran kontrol. Juga, penggunaan pengecualian dalam Python tidak memperlambat kode di sekitarnya dan kode panggilan seperti di beberapa bahasa yang dikompilasi (yaitu CPython sudah mengimplementasikan kode untuk pengecekan pengecualian pada setiap langkah, terlepas dari apakah Anda benar-benar menggunakan pengecualian atau tidak).
Dengan kata lain, pemahaman Anda bahwa "pengecualian untuk yang luar biasa" adalah aturan yang masuk akal dalam beberapa bahasa lain, tetapi tidak untuk Python.
"Namun, jika itu termasuk dalam bahasa itu sendiri, pasti ada alasan yang bagus untuk itu, bukan?"
Selain membantu menghindari kondisi balapan, pengecualian juga sangat berguna untuk menarik loop luar penanganan kesalahan. Ini adalah optimasi yang diperlukan dalam bahasa yang ditafsirkan yang tidak cenderung memiliki gerakan kode invarian loop otomatis .
Selain itu, pengecualian dapat menyederhanakan kode sedikit dalam situasi umum di mana kemampuan untuk menangani suatu masalah jauh dari tempat masalah tersebut muncul. Sebagai contoh, adalah umum untuk memiliki kode panggilan kode antarmuka pengguna tingkat atas untuk logika bisnis yang pada gilirannya memanggil rutin tingkat rendah. Situasi yang timbul dalam rutinitas tingkat rendah (seperti catatan duplikat untuk kunci unik dalam akses basis data) hanya dapat ditangani dalam kode tingkat atas (seperti meminta kunci baru kepada pengguna yang tidak bertentangan dengan kunci yang ada). Penggunaan pengecualian untuk aliran kontrol semacam ini memungkinkan rutinitas tingkat menengah untuk sepenuhnya mengabaikan masalah dan dipisahkan dengan baik dari aspek kontrol aliran tersebut.
Ada posting blog yang bagus tentang perlunya pengecualian di sini .
Juga, lihat jawaban Stack Overflow ini: Apakah pengecualian benar-benar untuk kesalahan luar biasa?
"Apa alasan untuk mencoba-kecuali-yang lain ada?"
Klausa lain itu sendiri menarik. Ini berjalan ketika tidak ada pengecualian kecuali sebelum akhirnya-klausa. Itulah tujuan utamanya.
Tanpa klausa lain, satu-satunya pilihan untuk menjalankan kode tambahan sebelum finalisasi adalah praktik kikuk menambahkan kode ke klausa coba. Itu canggung karena berisiko meningkatkan pengecualian dalam kode yang tidak dimaksudkan untuk dilindungi oleh blok-coba.
Kasus penggunaan menjalankan kode tambahan yang tidak dilindungi sebelum finalisasi tidak sering muncul. Jadi, jangan berharap melihat banyak contoh dalam kode yang diterbitkan. Agak jarang.
Use-case lain untuk klausa lain adalah untuk melakukan tindakan yang harus terjadi ketika tidak ada pengecualian terjadi dan yang tidak terjadi ketika pengecualian ditangani. Sebagai contoh:
recip = float('Inf')
try:
recip = 1 / f(x)
except ZeroDivisionError:
logging.info('Infinite result')
else:
logging.info('Finite result')
Contoh lain terjadi pada pelari yang tidak terdaftar:
try:
tests_run += 1
run_testcase(case)
except Exception:
tests_failed += 1
logging.exception('Failing test case: %r', case)
print('F', end='')
else:
logging.info('Successful test case: %r', case)
print('.', end='')
Terakhir, penggunaan yang paling umum dari klausa lain dalam blok percobaan adalah untuk sedikit mempercantik (menyelaraskan hasil yang luar biasa dan hasil yang tidak luar biasa pada tingkat indentasi yang sama). Penggunaan ini selalu opsional dan tidak sepenuhnya diperlukan.
Sebuah
try
blok memungkinkan Anda untuk menangani kesalahan yang diharapkan. Theexcept
block hanya harus menangkap pengecualian Anda siap untuk menangani. Jika Anda menangani kesalahan yang tidak terduga, kode Anda mungkin melakukan hal yang salah dan menyembunyikan bug.Sebuah
else
klausa akan dieksekusi jika tidak ada kesalahan, dan dengan tidak mengeksekusi kode itu ditry
blok, Anda menghindari menangkap kesalahan yang tidak terduga. Sekali lagi, menangkap kesalahan yang tidak terduga dapat menyembunyikan bug.Contoh
Sebagai contoh:
Suite "coba, kecuali" memiliki dua klausa opsional,
else
danfinally
. Jadi sebenarnyatry-except-else-finally
.else
akan mengevaluasi hanya jika tidak ada pengecualian daritry
blok. Ini memungkinkan kami untuk menyederhanakan kode yang lebih rumit di bawah ini:jadi jika kita membandingkan suatu
else
dengan alternatif (yang mungkin membuat bug) kita melihat bahwa itu mengurangi garis-garis kode dan kita dapat memiliki basis kode yang lebih mudah dibaca, dirawat, dan kurang buggy.finally
finally
akan mengeksekusi tidak peduli apa, bahkan jika baris lain sedang dievaluasi dengan pernyataan pengembalian.Rusak dengan kode semu
Mungkin membantu untuk memecah ini, dalam bentuk sekecil mungkin yang menunjukkan semua fitur, dengan komentar. Anggap ini benar secara sintaksis (tetapi tidak bisa dijalankan kecuali nama-nama didefinisikan) pseudo-code dalam suatu fungsi.
Sebagai contoh:
Memang benar bahwa kita dapat memasukkan kode dalam
else
blok ditry
blok sebagai gantinya, di mana ia akan berjalan jika tidak ada pengecualian, tetapi bagaimana jika kode itu sendiri menimbulkan pengecualian dari jenis yang kita tangkap? Membiarkannya ditry
blok akan menyembunyikan bug itu.Kami ingin meminimalkan baris kode di
try
blok untuk menghindari penangkapan pengecualian yang tidak kami harapkan, dengan prinsip bahwa jika kode kami gagal, kami ingin kode tersebut gagal dengan keras. Ini adalah praktik terbaik .Dalam Python, sebagian besar pengecualian adalah kesalahan.
Kita dapat melihat hierarki pengecualian dengan menggunakan pydoc. Misalnya, dalam Python 2:
atau Python 3:
Akan memberi kita hierarki. Kita dapat melihat bahwa sebagian besar jenis
Exception
kesalahan, meskipun Python menggunakan beberapa dari mereka untuk hal-hal seperti mengakhirifor
loop (StopIteration
). Ini adalah hierarki Python 3:Seorang komentator bertanya:
Tidak, Anda tidak mengembalikan pengecualian, hanya jalankan kembali dengan telanjang
raise
untuk mempertahankan stacktrace.Atau, dalam Python 3, Anda bisa menaikkan pengecualian baru dan mempertahankan backtrace dengan rantai pengecualian:
Saya menguraikan jawaban saya di sini .
sumber
raise
atau melakukan chaining pengecualian - tapi itu lebih pada topik dan dibahas di sini: stackoverflow.com/q/2052390/541136 - Saya mungkin akan menghapus komentar ini setelah saya sudah melihat kamu telah melihat mereka.Python tidak berlangganan gagasan bahwa pengecualian hanya boleh digunakan untuk kasus luar biasa, pada kenyataannya idiomnya adalah 'minta maaf, bukan izin' . Ini berarti bahwa menggunakan pengecualian sebagai bagian rutin dari kontrol aliran Anda dapat diterima, dan pada kenyataannya, dianjurkan.
Ini umumnya hal yang baik, karena bekerja dengan cara ini membantu menghindari beberapa masalah (sebagai contoh nyata, kondisi lomba sering dihindari), dan cenderung membuat kode sedikit lebih mudah dibaca.
Bayangkan Anda memiliki situasi di mana Anda mengambil beberapa input pengguna yang perlu diproses, tetapi memiliki default yang sudah diproses. The
try: ... except: ... else: ...
Struktur membuat kode sangat mudah dibaca:Bandingkan dengan cara kerjanya dalam bahasa lain:
Perhatikan keunggulannya. Tidak perlu memeriksa nilai yang valid dan menguraikannya secara terpisah, mereka dilakukan sekali. Kode juga mengikuti perkembangan yang lebih logis, jalur kode utama pertama, diikuti oleh 'jika tidak berhasil, lakukan ini'.
Contohnya secara alami sedikit dibuat-buat, tetapi itu menunjukkan ada kasus untuk struktur ini.
sumber
Jawabannya adalah tergantung pada konteks. Jika kamu melakukan ini:
Ini menunjukkan bahwa Anda tidak mengenal Python dengan baik. Fungsi ini diringkas dalam
dict.get
metode:Itu
try
/except
blok adalah cara yang jauh lebih visual berantakan dan verbose menulis apa yang bisa efisien mengeksekusi dalam satu baris dengan metode atom. Ada kasus lain di mana ini benar.Namun, itu tidak berarti bahwa kita harus menghindari semua penanganan pengecualian. Dalam beberapa kasus lebih disukai untuk menghindari kondisi balapan. Jangan periksa apakah ada file, coba buka saja, dan tangkap IOError yang sesuai. Demi kesederhanaan dan keterbacaan, cobalah untuk merangkum ini atau faktor itu sebagai yang sesuai.
Baca Zen Python , pahami bahwa ada prinsip-prinsip yang berada dalam ketegangan, dan waspadalah terhadap dogma yang terlalu bergantung pada salah satu pernyataan di dalamnya.
sumber
Lihat contoh berikut yang mengilustrasikan segala sesuatu tentang coba-kecuali-lain-akhirnya:
Implementasikan dan datang dengan:
sumber
Anda harus berhati-hati dalam menggunakan blok akhirnya, karena itu tidak sama dengan menggunakan blok lain di coba, kecuali. Blok akhirnya akan dijalankan terlepas dari hasil percobaan kecuali.
Karena semua orang telah mencatat menggunakan blok lain menyebabkan kode Anda lebih mudah dibaca, dan hanya berjalan ketika pengecualian tidak dilempar
sumber
Setiap kali Anda melihat ini:
Atau bahkan ini:
Pertimbangkan ini sebagai gantinya:
sumber
Hanya karena tidak ada orang lain yang memposting pendapat ini, saya akan mengatakan
Berbeda dengan kata kunci
try
,,except
danfinally
, maknaelse
klausa tidak jelas; itu kurang mudah dibaca. Karena tidak sering digunakan, itu akan menyebabkan orang yang membaca kode Anda ingin memeriksa ulang dokumen untuk memastikan mereka memahami apa yang terjadi.(Saya menulis jawaban ini justru karena saya menemukan
try/except/else
di basis kode saya dan itu menyebabkan wtf saat dan memaksa saya untuk melakukan beberapa pencarian di Google).Jadi, di mana pun saya melihat kode seperti contoh OP:
Saya lebih suka refactor
<1> pengembalian eksplisit, dengan jelas menunjukkan bahwa, dalam kasus pengecualian, kami selesai bekerja
<2> sebagai efek samping minor yang bagus, kode yang dulunya berada di
else
blok disimpulkan oleh satu level.sumber
Ini adalah cuplikan sederhana saya tentang cara memahami blok coba-kecuali-lain-akhirnya di Python:
Mari coba div 1/1:
Mari coba div 1/0
sumber
OP, ANDA BENAR. Yang lain setelah mencoba / kecuali dalam Python jelek . itu mengarah ke objek kontrol aliran lain di mana tidak ada yang diperlukan:
Setara yang sangat jelas adalah:
Ini jauh lebih jelas daripada klausa lain. Yang lain setelah mencoba / kecuali tidak sering ditulis, sehingga perlu beberapa saat untuk mengetahui apa implikasinya.
Hanya karena Anda BISA melakukan sesuatu, tidak berarti Anda HARUS melakukan sesuatu.
Banyak fitur telah ditambahkan ke bahasa karena seseorang mengira itu mungkin berguna. Masalahnya adalah, semakin banyak fitur, hal-hal yang kurang jelas dan jelas adalah karena orang biasanya tidak menggunakan bel dan peluit itu.
Hanya 5 sen saya di sini. Saya harus ikut serta dan membersihkan banyak kode yang ditulis oleh mahasiswa tahun pertama dari pengembang perguruan tinggi yang berpikir mereka cerdas dan ingin menulis kode dengan cara yang ketat, sangat efisien ketika itu hanya membuatnya berantakan untuk mencoba dan membaca / memodifikasi nanti. Saya memilih keterbacaan setiap hari dan dua kali pada hari Minggu.
sumber
print
pernyataan Anda yang gagal. Apa yang terjadi jikax = blah()
mengembalikan astr
, tetapi pernyataan cetak Andaprint 'just succeeded with blah. x == %d' % x
? Sekarang Anda memiliki hasilTypeError
yang dibuat di mana Anda tidak siap untuk menanganinya; Anda sedang memeriksax = blah()
untuk menemukan sumber pengecualian, dan bahkan tidak ada di sana. Saya telah melakukan ini (atau yang setara) lebih dari sekali di manaelse
saya tidak akan melakukan kesalahan ini. Sekarang saya tahu lebih baik. :-Delse
klausul bukanlah pernyataan yang cukup, dan sampai Anda terbiasa untuk itu, itu tidak intuitif. Tapi kemudian, begitu jugafinally
ketika saya pertama kali mulai menggunakannya ...else
klausa tidak ditangkap olehexcept
.x = blah()
untuk menemukan sumber pengecualian", Setelahtraceback
mengapa Anda memeriksa sumber pengecualian dari tempat yang salah?