Pengaturan
Saya sering mengalami kesulitan menentukan kapan dan bagaimana menggunakan pengecualian. Mari kita perhatikan contoh sederhana: misalkan saya sedang menggores halaman web, katakan " http://www.abevigoda.com/ ", untuk menentukan apakah Abe Vigoda masih hidup. Untuk melakukan ini, yang perlu kita lakukan adalah mengunduh halaman dan mencari waktu di mana frasa "Abe Vigoda" muncul. Kami mengembalikan penampilan pertama, karena itu termasuk status Abe. Secara konseptual, akan terlihat seperti ini:
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Di mana parse_abe_status(s)
mengambil string dari bentuk "Abe Vigoda adalah sesuatu " dan mengembalikan bagian " sesuatu ".
Sebelum Anda berargumen bahwa ada banyak cara yang lebih baik dan lebih kuat untuk menggores halaman ini untuk status Abe, ingat bahwa ini hanyalah contoh sederhana dan dibuat-buat yang digunakan untuk menyoroti situasi umum yang saya alami.
Sekarang, di mana kode ini dapat mengalami masalah? Di antara kesalahan lain, beberapa kesalahan "yang diharapkan" adalah:
download_page
mungkin tidak dapat mengunduh halaman, dan melemparIOError
.- URL mungkin tidak mengarah ke halaman kanan, atau halaman tersebut diunduh secara salah, sehingga tidak ada klik.
hits
adalah daftar kosong, lalu. - Halaman web telah diubah, mungkin membuat asumsi kami tentang halaman yang salah. Mungkin kita mengharapkan 4 menyebutkan Abe Vigoda, tetapi sekarang kita menemukan 5.
- Untuk beberapa alasan,
hits[0]
mungkin bukan string dari bentuk "Abe Vigoda adalah sesuatu ", dan karenanya tidak dapat diuraikan dengan benar.
Kasus pertama sebenarnya bukan masalah bagi saya: sebuah IOError
dilemparkan dan dapat ditangani oleh penelepon fungsi saya. Jadi mari kita pertimbangkan kasus-kasus lain dan bagaimana saya bisa menanganinya. Tetapi pertama-tama, mari kita asumsikan bahwa kita menerapkan parse_abe_status
dengan cara paling bodoh yang mungkin:
def parse_abe_status(s):
return s[13:]
Yaitu, tidak melakukan pengecekan kesalahan. Sekarang, ke opsi:
Opsi 1: Kembali None
Saya dapat memberi tahu penelepon bahwa ada yang tidak beres dengan kembali None
:
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
if not hits:
return None
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Jika penelepon menerima None
dari fungsi saya, ia harus berasumsi bahwa tidak ada yang menyebutkan Abe Vigoda, dan ada yang salah. Tapi ini agak kabur, kan? Dan itu tidak membantu kasus di mana hits[0]
bukan apa yang kita pikirkan.
Di sisi lain, kita dapat memasukkan beberapa pengecualian:
Opsi 2: Menggunakan Pengecualian
Jika hits
kosong, sebuah IndexError
akan terlempar ketika kita mencoba hits[0]
. Tapi si penelepon seharusnya tidak diharapkan menangani masalah yang IndexError
dilemparkan oleh fungsi saya, karena dia tidak tahu dari mana IndexError
datangnya; itu bisa saja dibuang find_all_mentions
, untuk semua yang dia tahu. Jadi kami akan membuat kelas pengecualian khusus untuk menangani ini:
class NotFoundError(Exception):
"""Throw this when something can't be found on a page."""
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
try:
hits[0]
except IndexError:
raise NotFoundError("No mentions found.")
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Sekarang bagaimana jika halaman telah berubah dan ada jumlah hit yang tidak terduga? Ini bukan bencana, karena kodenya mungkin masih berfungsi, tetapi pemanggil mungkin ingin ekstra hati - hati, atau dia mungkin ingin mencatat peringatan. Jadi saya akan memberikan peringatan:
class NotFoundError(Exception):
"""Throw this when something can't be found on a page."""
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
try:
hits[0]
except IndexError:
raise NotFoundError("No mentions found.")
# say we expect four hits...
if len(hits) != 4:
raise Warning("An unexpected number of hits.")
logger.warning("An unexpected number of hits.")
# parse the first hit for his status
status = parse_abe_status(hits[0])
# he's either alive or dead
return status == "alive"
Terakhir, kita mungkin menemukan bahwa status
itu tidak hidup atau mati. Mungkin, untuk beberapa alasan aneh, hari ini ternyata demikian comatose
. Maka saya tidak ingin kembali False
, karena itu menyiratkan bahwa Abe sudah mati. Apa yang harus saya lakukan di sini? Lempar pengecualian, mungkin. Tapi jenis apa? Haruskah saya membuat kelas pengecualian khusus?
class NotFoundError(Exception):
"""Throw this when something can't be found on a page."""
def get_abe_status(url):
# download the page
page = download_page(url)
# get all mentions of Abe Vigoda
hits = page.find_all_mentions("Abe Vigoda")
try:
hits[0]
except IndexError:
raise NotFoundError("No mentions found.")
# say we expect four hits...
if len(hits) != 4:
raise Warning("An unexpected number of hits.")
logger.warning("An unexpected number of hits.")
# parse the first hit for his status
status = parse_abe_status(hits[0])
if status not in ['alive', 'dead']:
raise SomeTypeOfError("Status is an unexpected value.")
# he's either alive or dead
return status == "alive"
Opsi 3: Di suatu tempat di antara keduanya
Saya pikir metode kedua, dengan pengecualian, lebih disukai, tetapi saya tidak yakin apakah saya menggunakan pengecualian dengan benar di dalamnya. Saya ingin tahu bagaimana programmer yang lebih berpengalaman akan menangani ini.