Konsensus umum “jangan gunakan pengecualian!” Sebagian besar berasal dari bahasa lain dan bahkan ada yang sudah usang.
Dalam C ++, melempar pengecualian sangat mahal karena “stack unwinding”. Setiap deklarasi variabel lokal seperti with
pernyataan dalam Python, dan objek dalam variabel itu dapat menjalankan destruktor. Destructor ini dieksekusi ketika pengecualian dilemparkan, tetapi juga ketika kembali dari suatu fungsi. “RAII idiom” ini adalah fitur bahasa yang tidak terpisahkan dan sangat penting untuk menulis kode yang kuat dan benar - jadi RAII versus pengecualian murah merupakan tradeoff yang C ++ putuskan untuk RAII.
Pada awal C ++, banyak kode tidak ditulis dengan cara pengecualian-aman: kecuali Anda benar-benar menggunakan RAII, mudah bocor memori dan sumber daya lainnya. Jadi, melempar pengecualian akan membuat kode itu salah. Ini tidak lagi masuk akal karena bahkan pustaka standar C ++ menggunakan pengecualian: Anda tidak bisa berpura-pura pengecualian tidak ada. Namun, pengecualian masih menjadi masalah saat menggabungkan kode C dengan C ++.
Di Jawa, setiap pengecualian memiliki jejak tumpukan yang terkait. Jejak tumpukan sangat berharga saat men-debug kesalahan, tetapi usaha yang sia-sia ketika pengecualian tidak pernah dicetak, misalnya karena itu hanya digunakan untuk aliran kontrol.
Jadi dalam bahasa-bahasa itu pengecualian "terlalu mahal" untuk digunakan sebagai aliran kontrol. Dalam Python ini kurang dari masalah dan pengecualian jauh lebih murah. Selain itu, bahasa Python sudah menderita beberapa overhead yang membuat biaya pengecualian tidak terlihat dibandingkan dengan konstruksi aliran kontrol lainnya: misalnya memeriksa apakah entri dikt ada dengan tes keanggotaan eksplisitif key in the_dict: ...
umumnya sama cepatnya dengan hanya mengakses entri the_dict[key]; ...
dan memeriksa apakah Anda dapatkan KeyError. Beberapa fitur bahasa integral (misalnya generator) dirancang dalam hal pengecualian.
Jadi, sementara tidak ada alasan teknis untuk secara khusus menghindari pengecualian dalam Python, masih ada pertanyaan apakah Anda harus menggunakannya alih-alih mengembalikan nilai. Masalah tingkat desain dengan pengecualian adalah:
sama sekali tidak jelas. Anda tidak dapat dengan mudah melihat fungsi dan melihat pengecualian yang dilemparkannya, sehingga Anda tidak selalu tahu harus menangkap apa. Nilai kembali cenderung lebih didefinisikan dengan baik.
pengecualian adalah aliran kontrol non-lokal yang memperumit kode Anda. Saat Anda melempar pengecualian, Anda tidak tahu di mana aliran kontrol akan dilanjutkan. Untuk kesalahan yang tidak dapat segera ditangani, ini mungkin ide yang baik, ketika memberi tahu penelepon Anda tentang kondisi ini sama sekali tidak perlu.
Budaya Python umumnya miring mendukung pengecualian, tetapi mudah untuk berlebihan. Bayangkan sebuah list_contains(the_list, item)
fungsi yang memeriksa apakah daftar tersebut berisi item yang sama dengan item itu. Jika hasilnya dikomunikasikan melalui pengecualian yang benar-benar menjengkelkan, karena kita harus menyebutnya seperti ini:
try:
list_contains(invited_guests, person_at_door)
except Found:
print("Oh, hello {}!".format(person_at_door))
except NotFound:
print("Who are you?")
Mengembalikan bool akan jauh lebih jelas:
if list_contains(invited_guests, person_at_door):
print("Oh, hello {}!".format(person_at_door))
else:
print("Who are you?")
Jika fungsi sudah seharusnya mengembalikan nilai, maka mengembalikan nilai khusus untuk kondisi khusus agak rawan kesalahan, karena orang akan lupa untuk memeriksa nilai ini (itu mungkin penyebab 1/3 dari masalah di C). Pengecualian biasanya lebih tepat.
Contoh yang baik adalah pos = find_string(haystack, needle)
fungsi yang mencari kemunculan pertama needle
string dalam string `haystack, dan mengembalikan posisi awal. Tetapi bagaimana jika tali jerami tidak mengandung benang jarum?
Solusi oleh C dan ditiru oleh Python adalah mengembalikan nilai khusus. Dalam C ini adalah pointer nol, dengan Python ini -1
. Ini akan menghasilkan hasil yang mengejutkan ketika posisi digunakan sebagai indeks string tanpa memeriksa, terutama seperti -1
indeks yang valid dalam Python. Di C, pointer NULL Anda setidaknya akan memberi Anda segfault.
Dalam PHP, nilai khusus dari jenis yang berbeda dikembalikan: boolean FALSE
bukan bilangan bulat. Ternyata ini sebenarnya tidak lebih baik karena aturan konversi implisit bahasa (tetapi perhatikan bahwa dalam Python juga boolean dapat digunakan sebagai ints!). Fungsi yang tidak mengembalikan tipe yang konsisten umumnya dianggap sangat membingungkan.
Varian yang lebih kuat adalah dengan melemparkan pengecualian ketika string tidak dapat ditemukan, yang memastikan bahwa selama aliran kontrol normal tidak mungkin untuk secara tidak sengaja menggunakan nilai khusus sebagai pengganti nilai biasa:
try:
pos = find_string(haystack, needle)
do_something_with(pos)
except NotFound:
...
Atau, selalu mengembalikan jenis yang tidak dapat digunakan secara langsung tetapi harus dibuka dulu dapat digunakan, misalnya tuple bool hasil di mana boolean menunjukkan apakah pengecualian terjadi atau jika hasilnya dapat digunakan. Kemudian:
pos, ok = find_string(haystack, needle)
if not ok:
...
do_something_with(pos)
Ini memaksa Anda untuk menangani masalah dengan segera, tetapi itu menjengkelkan dengan sangat cepat. Ini juga mencegah Anda dari fungsi chaining dengan mudah. Setiap panggilan fungsi sekarang membutuhkan tiga baris kode. Golang adalah bahasa yang menganggap gangguan ini layak untuk keselamatan.
Jadi untuk meringkas, pengecualian tidak sepenuhnya tanpa masalah dan dapat digunakan secara berlebihan, terutama ketika mereka mengganti nilai pengembalian "normal". Tetapi ketika digunakan untuk memberi sinyal kondisi khusus (tidak harus hanya kesalahan), maka pengecualian dapat membantu Anda mengembangkan API yang bersih, intuitif, mudah digunakan, dan sulit disalahgunakan.