Bagaimana Tidak Menangani Pengecualian dengan Python
Saya melihat banyak orang menangani pengecualian dengan cara yang salah. Mungkin ini juga berlaku untuk Anda. Apakah situasi berikut terdengar familiar?
Anda sedang menulis beberapa kode, tetapi Anda tahu bahwa perpustakaan yang Anda gunakan mungkin menimbulkan pengecualian. Anda tidak ingat yang mana, tepatnya. Pada titik ini, tergoda untuk menggunakan apa yang disebut blok catch-all dan melanjutkan hal-hal yang menyenangkan.
Daftar isi
Cara terburuk untuk melakukannya
Yang terburuk yang dapat Anda lakukan adalah membuat blok coba-kecuali yang menangkap apa pun. Dengan catch-all, maksud saya seperti:
try:
...
except:
pass
Blok tangkap semua seperti ini buruk karena:
Anda tidak tahu pengecualian apa yang mungkin muncul (lebih lanjut tentang ini nanti).
Kami menyembunyikan pengecualian dengan menggunakan pass secara diam-diam alih-alih mencatat kesalahan.
Selain itu, pengecualian yang kosong akan menangkap semuanya, termasuk KeyboardInterrupt (kontrol + c), SystemExit , dan bahkan NameErrors ! Ini berarti bahwa kode berikut tidak dapat dihentikan dengan bersih:
from time import sleep
while True:
try:
print("Try and stop me")
sleep(1)
except:
print("Don't.. stop.. me now!")
Jangan ragu untuk mencobanya. Anda perlu menutup jendela terminal atau mematikan proses Python untuk menghentikan program ini.
Cara yang lebih baik untuk menangkap semua pengecualian
Sebaliknya, saat menggunakan except Exception , meskipun masih merupakan cara cepat dan kotor untuk menangkap terlalu banyak pengecualian, setidaknya Anda dapat menghentikan proses yang berjalan dengan benar:
from time import sleep
while True:
try:
print("Try and stop me")
sleep(1)
except Exception:
print("Ok I'll stop!")
Saat menangkap Exception Anda tidak akan menangkap SystemExit , KeyboardInterrupt dan pengecualian lainnya. Mengapa demikian, Anda bertanya?
Semua pengecualian mewarisi dari kelas yang disebut BaseException . Menurut dokumentasi resmi:“Dalam try pernyataan dengan except klausa yang menyebutkan kelas tertentu, klausa itu juga menangani kelas pengecualian apa pun yang berasal dari kelas itu.” except yang kosong setara dengan except BaseException , maka ia akan menangkap semua kemungkinan pengecualian.
Sebaliknya, kelas Exception didefinisikan sebagai:“Semua pengecualian yang ada di dalam dan tidak keluar dari sistem diturunkan dari kelas ini. Semua pengecualian yang ditentukan pengguna juga harus diturunkan dari kelas ini.”
Lebih buruk lagi
Dalam contoh berikut, kami menggunakan perpustakaan os untuk mendapatkan direktori kerja saat ini. Namun, jari kelingking saya yang gemuk salah ketik:
import os
try:
working_dir = os.getcdw()
print(working_dir)
except:
print('error')
Karena os.getcdw bukan fungsi dalam modul os, NameError dilempar. Alih-alih gagal, klausa kecuali akan menangkap kesalahan, mencetak 'kesalahan' dan program akan terus berlanjut meskipun kesalahan ketik kami mencolok. Sayangnya, yang ini tidak dapat dipecahkan dengan menangkap Exception baik!
Ternyata, trik kecil kita dari langkah pertama ini bukanlah solusi untuk semua masalah kita. Jadi apa yang seharusnya kita lakukan?
Tangkap apa yang bisa Anda tangani
Ungkapan yang sering terdengar tentang exception adalah:catch what you can handle . Banyak pengembang tergoda untuk langsung menangani pengecualian, sementara seringkali lebih baik membiarkan pengecualian menyebar ke bagian program Anda yang benar-benar dapat menanganinya.
Misalnya, perhatikan bagian editor teks yang membuka dan memuat file, sebut saja OpenFile kelas. Jika pengguna meminta untuk membuka file yang tidak ada, Anda dapat langsung menangani kesalahan itu, atau membiarkannya menyebar.
Dalam hal ini, lebih baik untuk menyebarkan pengecualian ke pemanggil, karena OpenFile tidak tahu seberapa buruk pengecualian ini untuk penelepon. Penelepon dapat menangani situasi dengan berbagai cara:
Itu bisa membuat file baru dengan nama itu dan melanjutkan
Mungkin penelepon membutuhkan file tersebut untuk berada di sana, dalam hal ini ia dapat menampilkan dialog kesalahan untuk memberi tahu pengguna bahwa file ini tidak ada.
Bagaimanapun, ini bukan OpenFile kelas untuk memutuskan apa yang harus dilakukan jika terjadi FileNotFoundError .
Jadi haruskah pengecualian selalu disebarkan? Tidak. Kemungkinan pengecualian yang dapat ditangani di kelas FileOpen, adalah TimeoutError . Anda mungkin ingin mencoba lagi beberapa kali, misalnya, tanpa mengganggu penelepon dengan kesalahan. Ini adalah pengecualian yang OpenFile dapat menanganinya, jadi tidak apa-apa untuk menangkapnya dan mencoba lagi.
Kesimpulan
Anda seharusnya tidak menangkap lebih banyak pengecualian daripada yang dapat Anda tangani. Selimut kecuali blok adalah resep untuk bug dan kode yang tidak dapat diprediksi. Dengan kata lain:tangkap apa yang bisa Anda tangani.
Jika Anda menulis kode dengan mempertimbangkan matra 'tangkap apa yang dapat Anda tangani', menulis blok tangkap semua melanggar semua aturan. Jadi tolong, berhenti melakukannya. Sebagai latihan, Anda dapat meninjau kembali beberapa kode yang ada dan melihat apakah kode tersebut dapat ditingkatkan dengan pengetahuan baru ini!