Haruskah saya menguji if
sesuatu yang valid atau hanya try
untuk melakukannya dan menangkap pengecualian?
- Apakah ada dokumentasi kuat yang mengatakan bahwa satu cara lebih disukai?
- Apakah satu cara lebih pythonic ?
Misalnya, haruskah saya:
if len(my_list) >= 4:
x = my_list[3]
else:
x = 'NO_ABC'
Atau:
try:
x = my_list[3]
except IndexError:
x = 'NO_ABC'
Beberapa pemikiran ...
PEP 20 mengatakan:
Kesalahan tidak boleh lewat diam-diam.
Kecuali dibungkam secara eksplisit.
Haruskah menggunakan a try
alih - alih an if
diartikan sebagai kesalahan lewat diam-diam? Dan jika demikian, apakah Anda secara eksplisit membungkamnya dengan menggunakannya dengan cara ini, sehingga membuatnya oke?
Saya tidak mengacu pada situasi di mana Anda hanya dapat melakukan sesuatu dengan 1 cara; sebagai contoh:
try:
import foo
except ImportError:
import baz
if index in mylist
menguji apakah indeks adalah elemen dari mylist, bukan indeks yang mungkin. Anda justru menginginkannyaif index < len(mylist)
.if/else
try/catch
Dalam kasus khusus ini, Anda harus menggunakan sesuatu yang lain sama sekali:
x = myDict.get("ABC", "NO_ABC")
Namun secara umum: Jika Anda berharap pengujian sering gagal, gunakan
if
. Jika pengujian relatif mahal daripada hanya mencoba operasi dan menangkap pengecualian jika gagal, gunakantry
. Jika tidak satu pun dari kondisi ini berlaku, lakukan apa pun yang lebih mudah dibaca.sumber
Menggunakan
try
danexcept
secara langsung daripada di dalamif
penjaga harus selalu dilakukan jika ada kemungkinan kondisi balapan. Misalnya, jika Anda ingin memastikan bahwa direktori ada, jangan lakukan ini:import os, sys if not os.path.isdir('foo'): try: os.mkdir('foo') except OSError, e print e sys.exit(1)
Jika utas atau proses lain membuat direktori antara
isdir
danmkdir
, Anda akan keluar. Sebaliknya, lakukan ini:import os, sys, errno try: os.mkdir('foo') except OSError, e if e.errno != errno.EEXIST: print e sys.exit(1)
Itu hanya akan keluar jika direktori 'foo' tidak dapat dibuat.
sumber
Jika sepele untuk memeriksa apakah sesuatu akan gagal sebelum Anda melakukannya, Anda mungkin harus mendukungnya. Lagi pula, membuat pengecualian (termasuk pelacakan balik yang terkait) membutuhkan waktu.
Pengecualian harus digunakan untuk:
break
tidak membuat Anda cukup jauh), atau ...Perhatikan bahwa seringkali, jawaban sebenarnya adalah "tidak keduanya" - misalnya, pada contoh pertama Anda, yang seharusnya Anda lakukan hanyalah menggunakan
.get()
untuk memberikan default:x = myDict.get('ABC', 'NO_ABC')
sumber
if 'ABC' in myDict: x = myDict['ABC']; else: x = 'NO_ABC'
sebenarnya seringkali lebih cepat daripada menggunakanget
, sayangnya. Tidak mengatakan ini adalah kriteria yang paling penting, tetapi itu adalah sesuatu yang harus diperhatikan.if / else
dantry / except
dapat memiliki tempat mereka bahkan ketika ada alternatif khusus kasus karena mereka memiliki karakteristik kinerja yang berbeda..get()
adalah pencarian atribut dan overhead panggilan fungsi pada tingkat Python; menggunakan kata kunci pada built-in pada dasarnya langsung ke C. Saya tidak berpikir itu akan menjadi terlalu cepat dalam waktu dekat. Sejauhif
vs.try
, metode read dict.get () mengembalikan sebuah pointer yang memiliki beberapa info performa. Rasio hit untuk miss matter (try
bisa lebih cepat jika kuncinya hampir selalu ada) seperti halnya ukuran kamus.Seperti yang disebutkan oleh posting lain, itu tergantung pada situasinya. Ada beberapa bahaya dengan menggunakan coba / kecuali sebagai pengganti memeriksa validitas data Anda terlebih dahulu, terutama saat menggunakannya pada proyek yang lebih besar.
mis., misalkan Anda memiliki:
try: x = my_list[index_list[3]] except IndexError: x = 'NO_ABC'
IndexError tidak mengatakan apa-apa tentang apakah itu terjadi saat mencoba mendapatkan elemen index_list atau my_list.
sumber
Menggunakan
try
berarti mengakui bahwa suatu kesalahan mungkin berlalu, yang merupakan kebalikan dari membuatnya berlalu secara diam-diam. Menggunakanexcept
menyebabkannya tidak lewat sama sekali.Penggunaan
try: except:
lebih disukai dalam kasus di manaif: else:
logika lebih rumit. Sederhana lebih baik daripada kompleks; kompleks lebih baik daripada rumit; dan lebih mudah meminta maaf daripada izin.Apa "kesalahan tidak boleh lewat diam-diam" adalah peringatan tentang, adalah kasus di mana kode dapat memunculkan pengecualian yang Anda ketahui, dan di mana desain Anda mengakui kemungkinan itu, tetapi Anda belum merancang dengan cara untuk menangani pengecualian. Membungkam kesalahan secara eksplisit, dalam pandangan saya, akan melakukan sesuatu seperti
pass
dalamexcept
blok, yang seharusnya hanya dilakukan dengan pemahaman bahwa "tidak melakukan apa-apa" sebenarnya adalah penanganan kesalahan yang benar dalam situasi tertentu. (Ini adalah salah satu dari beberapa saat di mana saya merasa komentar dalam kode yang ditulis dengan baik mungkin benar-benar diperlukan.)Namun, dalam contoh khusus Anda, tidak ada yang sesuai:
x = myDict.get('ABC', 'NO_ABC')
Alasan semua orang menunjukkan hal ini - meskipun Anda mengakui keinginan Anda untuk memahami secara umum, dan ketidakmampuan untuk memberikan contoh yang lebih baik - adalah bahwa langkah-langkah yang setara sebenarnya ada di banyak kasus, dan mencarinya adalah langkah pertama dalam memecahkan masalah.
sumber
Setiap kali Anda menggunakan
try/except
aliran kontrol, tanyakan pada diri Anda:try
pemblokiran berhasil dan kapan gagal?try
blok?try
blok memunculkan pengecualian?try
blok berubah, apakah aliran kontrol Anda akan tetap berfungsi seperti yang diharapkan?Jika jawaban untuk satu atau lebih dari pertanyaan ini adalah 'tidak', mungkin ada banyak pengampunan untuk diminta; kemungkinan besar dari diri Anda di masa depan.
Sebuah contoh. Saya baru-baru ini melihat kode dalam proyek yang lebih besar yang terlihat seperti ini:
try: y = foo(x) except ProgrammingError: y = bar(x)
Berbicara dengan programmer ternyata aliran kontrol yang dimaksud adalah:
Ini berhasil karena
foo
membuat kueri database dan kueri akan berhasil jikax
berupa integer dan melemparProgrammingError
jikax
adalah daftar.Menggunakan
try/except
adalah pilihan yang buruk di sini:ProgrammingError
tidak memberikan masalah sebenarnya (yangx
bukan bilangan bulat), yang membuatnya sulit untuk melihat apa yang sedang terjadi.ProgrammingError
dinaikkan selama panggilan database, yang waktu limbah. Hal-hal akan menjadi sangat mengerikan jika ternyatafoo
menulis sesuatu ke database sebelum mengeluarkan pengecualian, atau mengubah status beberapa sistem lain.ProgrammingError
hanya dimunculkan ketikax
daftar bilangan bulat. Misalkan ada kesalahan ketik dalamfoo
query database. Ini mungkin juga menimbulkan aProgrammingError
. Konsekuensinya adalah yangbar(x)
sekarang juga dipanggil whenx
is a integer. Ini mungkin menimbulkan pengecualian samar atau menghasilkan hasil yang tidak terduga.try/except
blok menambahkan persyaratan untuk semua implementasi masa depanfoo
. Setiap kali kita berubahfoo
, sekarang kita harus memikirkan bagaimana menangani daftar dan memastikan bahwa itu melemparProgrammingError
dan tidak, katakanlah,AttributeError
kesalahan atau tidak sama sekali.sumber
Untuk arti umum, Anda dapat mempertimbangkan untuk membaca Idiom dan Anti-Idiom dengan Python: Pengecualian .
Dalam kasus khusus Anda, seperti yang dinyatakan orang lain, Anda harus menggunakan
dict.get()
:sumber