ฉันทามติทั่วไป“ อย่าใช้ข้อยกเว้น!” ส่วนใหญ่มาจากภาษาอื่นและบางครั้งก็ล้าสมัย
ใน C ++ การขว้างข้อยกเว้นนั้นมีค่าใช้จ่ายสูงมากเนื่องจาก“ stack unwinding” การประกาศตัวแปรโลคัลทุกครั้งเป็นเหมือนwith
คำสั่งใน Python และวัตถุในตัวแปรนั้นอาจเรียกใช้ destructors destructors เหล่านี้จะถูกดำเนินการเมื่อมีข้อยกเว้นจะถูกโยน แต่เมื่อกลับจากฟังก์ชั่น “ RAII idiom” นี้เป็นคุณสมบัติทางภาษาที่สำคัญและสำคัญอย่างยิ่งในการเขียนรหัสที่ถูกต้องและแม่นยำดังนั้นดังนั้น RAII กับข้อยกเว้นราคาถูกจึงเป็นข้อแลกเปลี่ยนที่ C ++ ตัดสินใจต่อ RAII
ในช่วงต้น C ++ โค้ดจำนวนมากไม่ได้ถูกเขียนขึ้นในลักษณะที่ปลอดภัยยกเว้น: ยกเว้นว่าคุณใช้จริง RAII มันเป็นเรื่องง่ายที่จะรั่วไหลของหน่วยความจำและทรัพยากรอื่น ๆ ดังนั้นการโยนข้อยกเว้นจะทำให้รหัสนั้นไม่ถูกต้อง สิ่งนี้ไม่สมเหตุสมผลอีกต่อไปเนื่องจากแม้แต่ไลบรารีมาตรฐาน C ++ ก็ใช้ข้อยกเว้น: คุณไม่สามารถทำท่าว่ามีข้อยกเว้นได้ อย่างไรก็ตามข้อยกเว้นยังคงมีปัญหาเมื่อรวมรหัส C กับ C ++
ใน Java ทุกข้อยกเว้นมีการติดตามสแต็กที่เกี่ยวข้อง การติดตามสแต็กมีค่ามากเมื่อทำการดีบักข้อผิดพลาด แต่ต้องใช้ความพยายามอย่างมากเมื่อไม่มีการพิมพ์ข้อยกเว้นเช่นเนื่องจากใช้สำหรับโฟลว์การควบคุมเท่านั้น
ดังนั้นในข้อยกเว้นภาษาเหล่านั้น "แพงเกินไป" ที่จะใช้เป็นโฟลว์ควบคุม ใน Python ปัญหานี้มีน้อยและข้อยกเว้นจะถูกกว่ามาก นอกจากนี้ภาษา Python แล้วทนทุกข์ทรมานจากค่าใช้จ่ายบางอย่างที่ทำให้ค่าใช้จ่ายของข้อยกเว้นสังเกตเมื่อเทียบกับโครงสร้างการควบคุมการไหลอื่น ๆ เช่นการตรวจสอบถ้ารายการ Dict ที่มีอยู่กับการทดสอบการเป็นสมาชิกอย่างชัดเจนif key in the_dict: ...
โดยทั่วไปว่าเป็นอย่างรวดเร็วเป็นเพียงแค่การเข้าถึงรายการthe_dict[key]; ...
และการตรวจสอบถ้าคุณ รับ KeyError คุณสมบัติทางภาษาที่สำคัญบางอย่าง (เช่นเครื่องกำเนิดไฟฟ้า) ได้รับการออกแบบในแง่ของข้อยกเว้น
ดังนั้นในขณะที่ไม่มีเหตุผลทางเทคนิคในการหลีกเลี่ยงข้อยกเว้นใน Python โดยเฉพาะยังคงมีคำถามว่าคุณควรใช้มันแทนที่จะเป็นค่าตอบแทนหรือไม่ ปัญหาระดับการออกแบบที่มีข้อยกเว้นคือ:
พวกเขาไม่ชัดเจนเลย คุณไม่สามารถดูฟังก์ชั่นได้อย่างง่ายดายและดูว่ามีข้อยกเว้นใดที่ทำให้คุณไม่เข้าใจ ค่าส่งคืนมีแนวโน้มที่จะมีความชัดเจนมากขึ้น
ข้อยกเว้นคือโฟลว์การควบคุมที่ไม่อยู่ในระบบซึ่งทำให้รหัสของคุณซับซ้อน เมื่อคุณโยนข้อยกเว้นคุณไม่ทราบว่าจะให้โฟลว์การควบคุมกลับมาทำงานต่อที่ใด สำหรับข้อผิดพลาดที่ไม่สามารถจัดการได้ในทันทีนี่เป็นความคิดที่ดีเมื่อแจ้งผู้โทรถึงเงื่อนไขว่าไม่จำเป็นทั้งหมด
โดยทั่วไปแล้ววัฒนธรรมของหลามนั้นมีลักษณะเป็นข้อยกเว้น แต่ก็ง่ายที่จะลงน้ำ ลองนึกภาพlist_contains(the_list, item)
ฟังก์ชั่นที่ตรวจสอบว่ารายการนั้นมีรายการเท่ากับรายการนั้นหรือไม่ หากผลการสื่อสารผ่านข้อยกเว้นที่น่ารำคาญอย่างยิ่งเพราะเราต้องเรียกมันว่า:
try:
list_contains(invited_guests, person_at_door)
except Found:
print("Oh, hello {}!".format(person_at_door))
except NotFound:
print("Who are you?")
การส่งคืนบูลจะชัดเจนมากขึ้น:
if list_contains(invited_guests, person_at_door):
print("Oh, hello {}!".format(person_at_door))
else:
print("Who are you?")
หากฟังก์ชั่นที่ควรจะคืนค่าแล้วส่งกลับค่าพิเศษสำหรับเงื่อนไขพิเศษค่อนข้างผิดพลาดได้ง่ายเพราะคนจะลืมที่จะตรวจสอบค่านี้ (นั่นอาจเป็นสาเหตุของปัญหา 1/3 ใน C) ข้อยกเว้นมักจะถูกต้องมากขึ้น
ตัวอย่างที่ดีคือpos = find_string(haystack, needle)
ฟังก์ชันที่ค้นหาการเกิดขึ้นครั้งแรกของneedle
สตริงในสตริง `haystack และส่งคืนตำแหน่งเริ่มต้น แต่ถ้าพวกเขาเป็นกองฟางไม่มีเข็มสตริง?
วิธีการแก้ปัญหาโดย C และเลียนแบบโดย Python คือการคืนค่าพิเศษ ใน C -1
นี้เป็นตัวชี้โมฆะในหลามนี้อยู่ สิ่งนี้จะนำไปสู่ผลลัพธ์ที่น่าประหลาดใจเมื่อมีการใช้ตำแหน่งเป็นดัชนีสตริงโดยไม่ตรวจสอบโดยเฉพาะอย่างยิ่ง-1
ดัชนีที่ถูกต้องใน Python ใน C ตัวชี้ NULL ของคุณอย่างน้อยจะให้ segfault
ใน PHP จะส่งคืนค่าพิเศษของประเภทที่แตกต่างนั่นคือบูลีนFALSE
แทนที่จะเป็นจำนวนเต็ม ตามที่ปรากฎว่าสิ่งนี้ไม่ได้ดีไปกว่านี้อีกแล้วเนื่องจากกฎการแปลงโดยนัยของภาษา (แต่โปรดทราบว่าใน Python รวมถึง booleans สามารถใช้เป็น ints!) ฟังก์ชั่นที่ไม่ส่งคืนชนิดที่สอดคล้องกันนั้นโดยทั่วไปถือว่ามีความสับสนมาก
ตัวแปรที่แข็งแกร่งกว่านั้นจะต้องทำการยกเว้นเมื่อไม่พบสตริงซึ่งทำให้แน่ใจว่าในระหว่างการควบคุมการไหลปกติมันเป็นไปไม่ได้ที่จะใช้ค่าพิเศษแทนค่าปกติโดยไม่ได้ตั้งใจ:
try:
pos = find_string(haystack, needle)
do_something_with(pos)
except NotFound:
...
อีกวิธีหนึ่งคือส่งคืนชนิดที่ไม่สามารถใช้โดยตรงได้ แต่ต้องสามารถนำกลับมาใช้ใหม่ได้ก่อนเช่น e-bool tuple ที่บูลีนระบุว่ามีข้อยกเว้นเกิดขึ้นหรือผลที่ได้นั้นสามารถใช้ได้ แล้ว:
pos, ok = find_string(haystack, needle)
if not ok:
...
do_something_with(pos)
นี่เป็นการบังคับให้คุณจัดการกับปัญหาในทันที แต่มันก็น่ารำคาญอย่างรวดเร็ว นอกจากนี้ยังป้องกันคุณจากการผูกมัดฟังก์ชั่นได้อย่างง่ายดาย การเรียกใช้ฟังก์ชันทุกอันต้องใช้รหัสสามบรรทัด Golang เป็นภาษาที่คิดว่าสิ่งนี้เป็นสิ่งที่คุ้มค่ากับความปลอดภัย
ดังนั้นเพื่อสรุปข้อยกเว้นไม่ได้ทั้งหมดโดยไม่มีปัญหาและสามารถใช้มากเกินไปแน่นอนโดยเฉพาะอย่างยิ่งเมื่อพวกเขาเปลี่ยนค่าตอบแทน "ปกติ" แต่เมื่อใช้เพื่อส่งสัญญาณเงื่อนไขพิเศษ (ไม่จำเป็นต้องเป็นแค่ข้อผิดพลาด) ดังนั้นข้อยกเว้นสามารถช่วยคุณในการพัฒนา API ที่สะอาดใช้งานง่ายใช้งานง่ายและยากที่จะใช้ในทางที่ผิด