เมื่อใช้ PyCharm IDE ใช้except:
โดยไม่มีการยกเว้นประเภททริกเกอร์การแจ้งเตือนจาก IDE Too broad
ที่ข้อยกเว้นนี้เป็น
ฉันควรเพิกเฉยต่อคำแนะนำนี้หรือไม่? หรือว่า Pythonic ระบุประเภทข้อยกเว้นเสมอ?
เมื่อใช้ PyCharm IDE ใช้except:
โดยไม่มีการยกเว้นประเภททริกเกอร์การแจ้งเตือนจาก IDE Too broad
ที่ข้อยกเว้นนี้เป็น
ฉันควรเพิกเฉยต่อคำแนะนำนี้หรือไม่? หรือว่า Pythonic ระบุประเภทข้อยกเว้นเสมอ?
คำตอบ:
การระบุประเภทข้อยกเว้นอย่างชัดเจนมักจะดีกว่าเสมอ หากคุณใช้except:
ประโยคเปล่าคุณอาจพบข้อยกเว้นอื่นนอกเหนือจากที่คุณคาดว่าจะจับได้ซึ่งสามารถซ่อนข้อบกพร่องหรือทำให้ยากต่อการดีบักโปรแกรมเมื่อพวกเขาไม่ได้ทำตามที่คุณคาดหวัง
ตัวอย่างเช่นหากคุณกำลังแทรกแถวลงในฐานข้อมูลคุณอาจต้องการตรวจจับข้อยกเว้นที่ระบุว่ามีแถวนั้นอยู่แล้วดังนั้นคุณจึงสามารถทำการอัปเดตได้
try:
insert(connection, data)
except:
update(connection, data)
หากคุณระบุ bare except:
คุณจะตรวจพบข้อผิดพลาดของซ็อกเก็ตที่ระบุว่าเซิร์ฟเวอร์ฐานข้อมูลล้มลง ทางที่ดีควรจับเฉพาะข้อยกเว้นที่คุณรู้วิธีจัดการ - มักจะดีกว่าที่โปรแกรมจะล้มเหลว ณ จุดที่เป็นข้อยกเว้นแทนที่จะดำเนินการต่อ แต่ทำงานในรูปแบบที่ไม่คาดคิดแปลก ๆ
กรณีหนึ่งที่คุณอาจต้องการใช้ bare except:
คือที่ระดับบนสุดของโปรแกรมที่คุณต้องใช้งานอยู่เสมอเช่นเซิร์ฟเวอร์เครือข่าย แต่คุณต้องระมัดระวังในการบันทึกข้อยกเว้นมิฉะนั้นจะไม่สามารถระบุได้ว่าเกิดอะไรขึ้น โดยทั่วไปควรมีเพียงที่เดียวในโปรแกรมที่ทำเช่นนี้
ควันหลงทั้งหมดนี้คือรหัสของคุณไม่ควรทำraise Exception('some message')
เพราะมันบังคับให้รหัสลูกค้ากับการใช้งานexcept:
(หรือexcept Exception:
ซึ่งเป็นเกือบเป็นเลว) คุณควรกำหนดข้อยกเว้นเฉพาะสำหรับปัญหาที่คุณต้องการส่งสัญญาณ (อาจสืบทอดมาจากคลาสย่อยข้อยกเว้นในตัวเช่นValueError
หรือTypeError
) หรือคุณควรเพิ่มข้อยกเว้นในตัวที่เฉพาะเจาะจง สิ่งนี้ช่วยให้ผู้ใช้รหัสของคุณระมัดระวังในการจับเฉพาะข้อยกเว้นที่ต้องการจัดการ
except:
จับได้ (เหนือสิ่งอื่นใด) NameError
และAttributeError
ดังนั้นหากคุณสะกดคำผิดในtry
บล็อก (เช่นฟังก์ชัน "แทรก" ของคุณถูกเรียกจริงinsert_one
เพราะมีคนไม่ให้ความสำคัญกับความสม่ำเสมอเท่าที่ควร) update()
มักจะพยายามที่จะเงียบ
main()
)?
except Exception:
จะจับNameError
และAttributeError
เกินไป สิ่งที่ทำให้การเปลือยexcept:
ไม่ดีคือการจับสิ่งของที่ไม่มีธุรกิจถูกจับได้เช่นSystemExit
(ยกขึ้นเมื่อคุณโทรexit
หรือsys.exit
และตอนนี้คุณได้ป้องกันการออกจากจุดประสงค์แล้ว) และKeyboardInterrupt
(อีกครั้งหากผู้ใช้โดนCtrl-C
คุณอาจไม่ต้องการ เพื่อให้ทำงานต่อไปเพื่อทำลายพวกเขา) เฉพาะอย่างหลังเท่านั้นที่สมเหตุสมผลที่จะจับและควรจับอย่างชัดเจน อย่างน้อยก็except Exception:
ให้ทั้งสองเผยแพร่ตามปกติ
คุณไม่ควรเพิกเฉยต่อคำแนะนำที่ล่ามให้กับคุณ
จากPEP-8 Style Guide สำหรับ Python:
เมื่อจับข้อยกเว้นให้พูดถึงข้อยกเว้นเฉพาะเมื่อทำได้แทนที่จะใช้ bare except: clause
ตัวอย่างเช่นใช้:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
ข้อยกเว้นเปล่า: อนุประโยคจะตรวจจับข้อยกเว้น SystemExit และ KeyboardInterrupt ทำให้ขัดขวางโปรแกรมด้วย Control-C ได้ยากขึ้นและสามารถปกปิดปัญหาอื่น ๆ หากคุณต้องการตรวจจับข้อยกเว้นทั้งหมดที่แสดงข้อผิดพลาดของโปรแกรมให้ใช้ข้อยกเว้น Exception: (bare except เทียบเท่ากับยกเว้น BaseException :)
หลักการง่ายๆคือ จำกัด การใช้ประโยค 'ยกเว้น' เปล่าไว้สองกรณี:
หากตัวจัดการข้อยกเว้นจะพิมพ์ออกมาหรือบันทึกการย้อนกลับ อย่างน้อยผู้ใช้จะทราบว่ามีข้อผิดพลาดเกิดขึ้น หากรหัสจำเป็นต้องทำการล้างข้อมูลบางอย่าง แต่ปล่อยให้ข้อยกเว้นแพร่กระจายขึ้นไปด้วยการเพิ่ม ลอง ... ในที่สุดก็เป็นวิธีที่ดีกว่าในการจัดการกับคดีนี้
ไม่ใช่เฉพาะสำหรับ Python นี้
จุดรวมของข้อยกเว้นคือการจัดการกับปัญหาให้ใกล้เคียงกับที่เกิดมากที่สุด
ดังนั้นคุณจึงเก็บรหัสที่อาจเกิดขึ้นในสถานการณ์พิเศษอาจทำให้เกิดปัญหาและความละเอียด "ถัดไป" ซึ่งกันและกัน
สิ่งนี้คือคุณไม่สามารถรู้ข้อยกเว้นทั้งหมดที่อาจเกิดขึ้นได้จากรหัสชิ้นส่วน สิ่งที่คุณสามารถรู้ได้ก็คือหากเป็นการบอกว่าไฟล์ไม่พบข้อยกเว้นคุณสามารถดักจับไฟล์และแจ้งให้ผู้ใช้รับไฟล์ที่ทำหรือยกเลิกฟังก์ชันได้
หากคุณลองจับรอบนั้นไม่ว่าจะมีปัญหาอะไรในรูทีนไฟล์ของคุณ (อ่านอย่างเดียวสิทธิ์ UAC ไม่ใช่ pdf จริงๆ ฯลฯ ) ทุกคนจะหล่นลงในไฟล์ของคุณไม่พบการจับและผู้ใช้ของคุณ กำลังกรีดร้อง "แต่มีอยู่รหัสนี้คืออึ"
ตอนนี้มีสถานการณ์สองสามอย่างที่คุณอาจจับได้ทุกอย่าง แต่ควรเลือกอย่างมีสติ
พวกเขาถูกจับเลิกทำการกระทำบางอย่างในพื้นที่ (เช่นการสร้างหรือล็อกทรัพยากร (เช่นการเปิดไฟล์บนดิสก์เพื่อเขียนเป็นต้น) จากนั้นคุณจะโยนข้อยกเว้นอีกครั้งเพื่อจัดการในระดับที่สูงขึ้น)
คุณไม่สนใจว่าทำไมมันถึงผิดพลาด การพิมพ์เช่น คุณอาจจับได้ตลอดเวลาว่ามีปัญหากับเครื่องพิมพ์ของคุณโปรดแยกแยะออกและอย่าฆ่าแอปพลิเคชันเพราะมัน ในทำนองเดียวกันก็ไร้ประโยชน์หากโค้ดของคุณดำเนินการชุดของงานแยกกันโดยใช้ตารางเวลาบางประเภทคุณจะไม่ต้องการให้ทุกอย่างตายเพราะงานหนึ่งล้มเหลว
หมายเหตุหากคุณทำตามข้างต้นฉันไม่สามารถแนะนำการบันทึกข้อยกเว้นบางประเภทได้เช่นลองใช้ catch end log ให้มากพอ
คุณจะจับเช่น Control-C ด้วยดังนั้นอย่าทำเช่นนั้นเว้นแต่คุณจะ "โยน" อีกครั้ง อย่างไรก็ตามในกรณีนี้คุณควรใช้ "สุดท้าย"
มักจะระบุชนิดยกเว้นมีหลายประเภทที่คุณไม่ต้องการที่จะจับเช่นSyntaxError
, KeyboardInterrupt
, MemoryError
ฯลฯ
except Exception:
หลีกเลี่ยงประเภทข้างต้นที่เราไม่ต้องการจับ?
except Exception
สบายดี.
except Exception
จับSyntaxError
และMemoryError
เพราะมันเป็นคลาสพื้นฐานของพวกเขา KeyboardInterrupt
, SystemExit
(ยกโดยsys.exit()
) ไม่ถูกจับ (เป็นคลาสย่อย BaseException ในทันที)
นี่คือสถานที่ที่ฉันใช้ยกเว้นไม่มีประเภท
นั่นคือการใช้งานหลักในรหัสของฉันสำหรับข้อยกเว้นที่ไม่ได้ตรวจสอบ
ฉันเพิ่มสิ่งนี้เสมอเพื่อไม่ให้โค้ดการผลิตหกสแต็กเทรซ
ฉันมีสองวิธีที่จะทำ:
ฉันชอบวิธีนี้มากกว่าฉันพบว่าง่ายกว่าในการตรวจจับว่าข้อยกเว้นใดควรถูกจับได้อย่างเหมาะสม: ฉัน "เห็น" ปัญหาได้ดีขึ้นเมื่อมีการบันทึกข้อยกเว้นระดับล่างโดยระดับที่สูงขึ้น
เพื่อนร่วมงานบางคนชอบวิธีนี้เนื่องจากรักษาข้อยกเว้นระดับล่างไว้ในฟังก์ชันระดับล่างโดยที่พวกเขา "เป็นของ"
ลองสิ่งนี้:
try:
#code
except ValueError:
pass
ฉันได้รับคำตอบจากลิงค์นี้หากมีใครพบปัญหานี้อีกลองดูสิ