การตั้งค่า
ฉันมักจะมีปัญหาในการกำหนดเวลาและวิธีใช้ข้อยกเว้น ลองพิจารณาตัวอย่างง่ายๆ: สมมติว่าฉันกำลังขูดหน้าเว็บให้พูดว่า " http://www.abevigoda.com/ " เพื่อพิจารณาว่า Abe Vigoda ยังมีชีวิตอยู่หรือไม่ ในการทำสิ่งนี้สิ่งที่เราต้องทำคือดาวน์โหลดหน้าและค้นหาเวลาที่วลี "Abe Vigoda" ปรากฏขึ้น เรากลับมาปรากฏตัวครั้งแรกเนื่องจากมีสถานะของ Abe ตามแนวคิดแล้วจะมีลักษณะดังนี้:
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"
ไหนparse_abe_status(s)
จะใช้เวลาสตริงของรูปแบบ "เอ็บ Vigoda เป็นบางสิ่งบางอย่าง " และผลตอบแทน " อะไรบางอย่าง " ส่วนหนึ่ง
ก่อนที่คุณจะยืนยันว่ามีวิธีที่ดีกว่าและแข็งแกร่งกว่าในการคัดลอกหน้านี้สำหรับสถานะของ Abe โปรดจำไว้ว่านี่เป็นเพียงตัวอย่างที่เรียบง่าย
ตอนนี้รหัสนี้จะพบปัญหาที่ไหน ท่ามกลางข้อผิดพลาดอื่น ๆ บางคน "คาดหวัง" คือ:
download_page
IOError
อาจจะไม่สามารถที่จะดาวน์โหลดหน้าและพ่น- URL อาจไม่ชี้ไปที่หน้าขวาหรือหน้าถูกดาวน์โหลดอย่างไม่ถูกต้องดังนั้นจึงไม่มีความนิยม
hits
เป็นรายการที่ว่างเปล่าแล้ว - หน้าเว็บมีการเปลี่ยนแปลงซึ่งอาจทำให้สมมติฐานของเราเกี่ยวกับหน้าเว็บผิด บางทีเราอาจคาดหวังถึง 4 กล่าวถึง Abe Vigoda แต่ตอนนี้เราพบ 5
- ด้วยเหตุผลบางอย่าง
hits[0]
อาจไม่ใช่สตริงของรูปแบบ "Abe Vigoda คือบางสิ่ง " และดังนั้นจึงไม่สามารถแยกวิเคราะห์ได้อย่างถูกต้อง
กรณีแรกไม่ใช่ปัญหาสำหรับฉันจริง ๆ : การIOError
โยนถูกและสามารถจัดการได้โดยผู้เรียกใช้ฟังก์ชันของฉัน ลองพิจารณากรณีอื่น ๆ และฉันจะจัดการกับมันอย่างไร แต่ก่อนอื่นสมมติว่าเราใช้งานparse_abe_status
ด้วยวิธีที่โง่ที่สุดเท่าที่จะทำได้:
def parse_abe_status(s):
return s[13:]
กล่าวคือมันไม่ได้ทำการตรวจสอบข้อผิดพลาดใด ๆ ตอนนี้ไปที่ตัวเลือก:
ตัวเลือกที่ 1: การกลับมา None
ฉันสามารถบอกผู้โทรได้ว่ามีบางอย่างผิดปกติจากการส่งคืน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"
หากผู้โทรได้รับNone
จากการทำงานของฉันเขาควรคิดว่าไม่มีการเอ่ยถึง Abe Vigoda และมีบางอย่างผิดปกติ แต่นี่มันคลุมเครือใช่มั้ย และมันไม่ได้ช่วยกรณีที่hits[0]
ไม่ใช่สิ่งที่เราคิดว่ามันเป็น
ในทางกลับกันเราสามารถใส่ข้อยกเว้นบางอย่าง:
ตัวเลือกที่ 2: การใช้ข้อยกเว้น
ถ้าhits
เป็นที่ว่างเปล่าเป็นจะถูกโยนเมื่อเราพยายามIndexError
hits[0]
แต่ผู้เรียกไม่ควรคาดหวังว่าจะจัดการกับIndexError
หน้าที่ของฉันเพราะเขาไม่รู้ว่ามันIndexError
มาจากไหน; มันอาจถูกโยนทิ้งไปfind_all_mentions
เพราะทุกสิ่งที่เขารู้ ดังนั้นเราจะสร้างคลาสยกเว้นที่กำหนดเองเพื่อจัดการกับสิ่งนี้:
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"
ตอนนี้จะเกิดอะไรขึ้นหากหน้าเว็บมีการเปลี่ยนแปลงและมีจำนวนครั้งที่เข้าชมที่ไม่คาดคิด นี่ไม่ใช่ความหายนะเนื่องจากรหัสอาจยังใช้งานได้ แต่ผู้โทรอาจต้องระมัดระวังเป็นพิเศษหรือเขาอาจต้องการบันทึกคำเตือน ดังนั้นฉันจะโยนคำเตือน:
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"
สุดท้ายเราอาจพบstatus
ว่าไม่ได้มีชีวิตอยู่หรือตายไป comatose
อาจจะด้วยเหตุผลบางอย่างที่แปลกวันนี้มันเปิดออกมาเป็น ถ้าอย่างนั้นฉันก็ไม่อยากกลับFalse
เพราะนั่นหมายความว่า Abe นั้นตายแล้ว ฉันควรทำอะไรที่นี่ โยนข้อยกเว้นอาจ แต่อะไรล่ะ ฉันควรสร้างคลาสยกเว้นที่กำหนดเองได้หรือไม่
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"
ตัวเลือก 3: อยู่ระหว่าง
ฉันคิดว่าวิธีที่สองที่มีข้อยกเว้นดีกว่า แต่ฉันไม่แน่ใจว่าฉันใช้ข้อยกเว้นอย่างถูกต้องภายในหรือไม่ ฉันอยากรู้ว่าโปรแกรมเมอร์ผู้มากประสบการณ์จะจัดการกับสิ่งนี้ได้อย่างไร