Ayar
İstisnaların ne zaman ve nasıl kullanılacağını belirlemekte sık sık sorun yaşıyorum. Basit bir örnek düşünelim: Abe Vigoda'nın hala hayatta olup olmadığını belirlemek için bir web sayfasını kazıyordum, " http://www.abevigoda.com/ " deyin . Bunu yapmak için tek yapmamız gereken sayfayı indirmek ve "Abe Vigoda" ifadesinin göründüğü zamanları aramak. Abe'nin durumunu da içerdiğinden, ilk görünümü geri getiriyoruz. Kavramsal olarak şöyle görünecektir:
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"
Nerede parse_abe_status(s)
"Abe Vigoda bir şeydir " şeklinde bir dize alır ve "bir şey " bölümünü döndürür .
Bu sayfayı Abe'nin durumu için kazımanın çok daha iyi ve daha sağlam yolları olduğunu iddia etmeden önce, bunun içinde bulunduğum ortak bir durumu vurgulamak için kullanılan basit ve anlaşılır bir örnek olduğunu unutmayın.
Şimdi, bu kod nerede sorunla karşılaşabilir? Diğer hataların yanı sıra, bazı "beklenen" olanlar:
download_page
sayfayı indiremeyebilir ve atarIOError
.- URL doğru sayfayı işaret etmeyebilir veya sayfa yanlış indirilmiş olabilir ve bu nedenle isabet yoktur.
hits
boş liste o zaman. - Web sayfası değiştirildi, muhtemelen sayfa hakkındaki varsayımlarımız yanlış. Belki Abe Vigoda'dan 4 bahsedeceğiz, ama şimdi 5 buluyoruz.
- Bazı nedenlerden dolayı,
hits[0]
"Abe Vigoda bir şeydir " biçiminde bir dize olmayabilir ve bu nedenle doğru şekilde ayrıştırılamaz.
İlk durum benim için gerçekten bir sorun değil: a IOError
atıldı ve fonksiyonumun arayanı tarafından ele alınabilir. Öyleyse diğer davaları ve bunları nasıl ele alabileceğimi ele alalım. Ama önce, parse_abe_status
mümkün olan en aptal şekilde uyguladığımızı varsayalım :
def parse_abe_status(s):
return s[13:]
Yani, herhangi bir hata kontrolü yapmaz. Şimdi, seçeneklere devam edin:
Seçenek 1: Dönüş None
Arayana geri dönerek bir şeylerin yanlış gittiğini söyleyebilirim 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"
Arayan None
benim işlevimi alırsa , Abe Vigoda'dan bahsedilmediğini varsaymalıdır ve bu nedenle bir şeyler ters gitti. Ama bu oldukça belirsiz, değil mi? Ve düşündüğümüz gibi olmayan duruma yardımcı hits[0]
olmaz.
Öte yandan, bazı istisnalar koyabiliriz:
2. Seçenek: İstisnaları Kullanma
Eğer hits
boş bir IndexError
biz çalıştığınızda atılacaktır hits[0]
. Ama arayanın IndexError
benim fonksiyonum tarafından atıldığı beklenmemelidir , çünkü bunun nereden IndexError
geldiğine dair bir fikri yoktur ; find_all_mentions
tüm bildiği için fırlatılabilirdi . Bu nedenle, bununla başa çıkmak için özel bir istisna sınıfı oluşturacağız:
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"
Şimdi sayfa değiştiyse ve beklenmedik sayıda isabet olursa ne olur? Kod hala işe yarayabileceğinden bu felaket değildir, ancak bir arayan ekstra dikkatli olmak isteyebilir veya bir uyarı kaydetmek isteyebilir. Bu yüzden bir uyarı vereceğim:
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"
Son olarak, bunun status
canlı ya da ölü olmadığını görebiliriz. Belki de garip bir nedenden ötürü, bugün ortaya çıktı comatose
. O zaman dönmek istemiyorum False
, çünkü Abe öldü. Burada ne yapmalıyım? Muhtemelen bir istisna atın. Ama ne tür? Özel bir istisna sınıfı oluşturmalı mıyım?
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"
Seçenek 3: Aralarında bir yer
İstisnalar hariç, ikinci yöntemin tercih edilebilir olduğunu düşünüyorum, ancak istisnaları doğru şekilde kullanıp kullanmadığımı bilmiyorum. Daha deneyimli programcıların bunu nasıl başaracağını merak ediyorum.