ในขณะที่คุณเดาถูกต้องมีสองด้าน: การจับข้อผิดพลาดใด ๆโดยการระบุชนิดข้อยกเว้นหลังจากexcept
นั้นและผ่านมันโดยไม่ต้องดำเนินการใด ๆ
คำอธิบายของฉันคือ“ บิต” อีกต่อไป - ดังนั้น tl มันแบ่งลงไปนี้:
- อย่าจับใด ๆ ที่ผิดพลาด ระบุข้อยกเว้นที่คุณพร้อมที่จะกู้คืนจากและจับเฉพาะข้อยกเว้นเหล่านั้นเสมอ
- พยายามหลีกเลี่ยงการผ่านในบล็อกยกเว้น เว้นแต่จะต้องการอย่างชัดเจนนี่เป็นสัญญาณที่ดี
แต่มาดูรายละเอียดกันดีกว่า:
อย่าจับข้อผิดพลาดใด ๆ
เมื่อใช้try
บล็อกคุณจะทำเช่นนี้เพราะคุณรู้ว่ามีข้อผิดพลาดเกิดขึ้น ด้วยเหตุนี้คุณจึงมีแนวคิดคร่าว ๆว่าอะไรที่จะแตกและมีข้อยกเว้นอะไรบ้างที่ถูกโยนทิ้งไป ในกรณีเช่นนี้คุณจับข้อยกเว้นเพราะคุณสามารถบวกกู้คืนจากมัน ซึ่งหมายความว่าคุณพร้อมสำหรับการยกเว้นและมีแผนทางเลือกบางอย่างที่คุณจะติดตามในกรณีที่มีข้อยกเว้นนั้น
ตัวอย่างเช่นเมื่อคุณขอให้ผู้ใช้ป้อนหมายเลขคุณสามารถแปลงการป้อนข้อมูลที่ใช้ซึ่งอาจยกint()
ValueError
คุณสามารถกู้คืนข้อมูลนั้นได้อย่างง่ายดายโดยขอให้ผู้ใช้ลองอีกครั้งดังนั้นการจับValueError
และให้ผู้ใช้อีกครั้งนั้นเป็นแผนที่เหมาะสม ตัวอย่างที่แตกต่างกันคือถ้าคุณต้องการอ่านการกำหนดค่าบางอย่างจากไฟล์และไฟล์นั้นไม่มีอยู่จริง เนื่องจากเป็นไฟล์กำหนดค่าคุณอาจมีการกำหนดค่าเริ่มต้นบางอย่างเป็นทางเลือกดังนั้นไฟล์จึงไม่จำเป็น ดังนั้นการจับFileNotFoundError
และเพียงแค่ใช้การตั้งค่าเริ่มต้นจะเป็นแผนที่ที่ดี ในทั้งสองกรณีนี้เรามีข้อยกเว้นเฉพาะอย่างยิ่งที่เราคาดหวังและมีแผนเฉพาะที่เท่าเทียมกันในการกู้คืนจากกรณีนี้ เช่นในแต่ละกรณีเราอย่างชัดเจนเท่านั้นexcept
ที่บาง ข้อยกเว้น
อย่างไรก็ตามหากเราต้องจับทุกอย่างแล้ว - นอกเหนือจากข้อยกเว้นเหล่านั้นที่เราพร้อมจะกู้คืน - ยังมีโอกาสที่เราจะได้รับข้อยกเว้นที่เราไม่คาดหวังและที่เราไม่สามารถกู้คืนได้แน่นอน หรือไม่ควรกู้คืนจาก
ลองดูตัวอย่างไฟล์การกำหนดค่าจากด้านบน ในกรณีที่ไฟล์หายไปเราเพิ่งใช้การกำหนดค่าเริ่มต้นของเราและอาจตัดสินใจในภายหลังเพื่อบันทึกการกำหนดค่าโดยอัตโนมัติ (ดังนั้นครั้งต่อไปไฟล์จะมีอยู่) ตอนนี้ลองนึกภาพเราจะได้รับIsADirectoryError
หรือPermissionError
แทน. ในกรณีเช่นนี้เราอาจไม่ต้องการดำเนินการต่อ เรายังคงสามารถใช้การกำหนดค่าเริ่มต้นของเราได้ แต่ภายหลังเราจะไม่สามารถบันทึกไฟล์ได้ และเป็นไปได้ว่าผู้ใช้หมายถึงมีการกำหนดค่าแบบกำหนดเองด้วยดังนั้นการใช้ค่าเริ่มต้นจึงไม่เป็นที่ต้องการ ดังนั้นเราต้องการบอกผู้ใช้เกี่ยวกับมันในทันทีและอาจยกเลิกการทำงานของโปรแกรมด้วย แต่นั่นไม่ใช่สิ่งที่เราต้องการทำที่ไหนสักแห่งในส่วนของโค้ด นี่เป็นสิ่งที่มีความสำคัญระดับแอปพลิเคชันดังนั้นจึงควรจัดการที่ด้านบน - ดังนั้นปล่อยให้ข้อยกเว้นฟองขึ้น
อีกตัวอย่างที่ง่ายกล่าวถึงในเอกสารสำนวน Python 2 ที่นี่มีการพิมพ์ผิดง่ายอยู่ในรหัสซึ่งทำให้มันผิด เพราะเราจะจับทุกข้อยกเว้นเรายังจับNameError
sและsSyntaxError
ทั้งสองเป็นข้อผิดพลาดที่เกิดขึ้นกับเราทุกคนในขณะที่การเขียนโปรแกรม; และทั้งคู่เป็นข้อผิดพลาดเราไม่ต้องการรวมอย่างแน่นอนเมื่อส่งรหัส แต่เนื่องจากเราจับสิ่งเหล่านี้เราจะไม่ทราบด้วยซ้ำว่าเกิดขึ้นที่นั่นและสูญเสียความช่วยเหลือในการดีบักอย่างถูกต้อง
แต่ก็มีข้อยกเว้นที่อันตรายกว่าซึ่งเราไม่ได้เตรียมไว้ ตัวอย่างเช่นSystemErrorมักจะเป็นสิ่งที่เกิดขึ้นได้ยากและเราไม่สามารถวางแผนได้ มันหมายถึงมีบางสิ่งที่ซับซ้อนมากขึ้นเกิดขึ้นสิ่งที่อาจทำให้เราไม่สามารถดำเนินงานปัจจุบันต่อไปได้
ไม่ว่าในกรณีใดมันไม่น่าเป็นไปได้มากนักที่คุณพร้อมสำหรับทุกอย่างในส่วนเล็ก ๆ ของรหัสดังนั้นนั่นจึงเป็นเรื่องจริงที่คุณควรจับเฉพาะข้อยกเว้นเหล่านั้นที่คุณเตรียมไว้ บางคนแนะนำให้จับอย่างน้อยException
เพราะมันจะไม่รวมสิ่งที่ชอบSystemExit
และสิ่งKeyboardInterrupt
ที่ออกแบบมาเพื่อยุติแอปพลิเคชันของคุณ แต่ฉันจะยืนยันว่านี่ยังไม่เจาะจงเกินไป มีสถานที่หนึ่งที่เดียวที่ผมเองยอมรับจับเป็นException
หรือเพียงแค่ใด ๆยกเว้นและอยู่ในตัวจัดการข้อยกเว้นระดับแอปพลิเคชันระดับโลกเดียวซึ่งมีจุดประสงค์เดียวในการบันทึกข้อยกเว้นใด ๆ ที่เราไม่ได้เตรียมไว้ ด้วยวิธีนี้เรายังสามารถเก็บข้อมูลได้มากที่สุดเกี่ยวกับข้อยกเว้นที่ไม่คาดคิดซึ่งเราสามารถใช้เพื่อขยายรหัสของเราเพื่อจัดการกับสิ่งเหล่านั้นอย่างชัดเจน (ถ้าเราสามารถกู้คืนได้จากพวกเขา) หรือในกรณีที่มีข้อผิดพลาด มันจะไม่เกิดขึ้นอีกครั้ง แต่แน่นอนว่าจะได้ผลก็ต่อเมื่อเราจับข้อยกเว้นเหล่านั้นที่เราคาดไว้แล้วเท่านั้นดังนั้นสิ่งที่เราไม่ได้คาดหวังจะเกิดฟองสบู่ขึ้นมาตามธรรมชาติ
พยายามหลีกเลี่ยงการส่งต่อยกเว้นบล็อก
เมื่อตรวจจับข้อยกเว้นเฉพาะที่เลือกไว้อย่างชัดเจนมีหลายสถานการณ์ที่เราจะไม่ต้องทำอะไรเลย ในกรณีเช่นนี้เพียงแค่มีexcept SomeSpecificException: pass
ไม่เป็นไร แม้ว่าส่วนใหญ่แล้วนี่ไม่ใช่กรณีที่เราน่าจะต้องการรหัสบางอย่างที่เกี่ยวข้องกับกระบวนการกู้คืน (ดังกล่าวข้างต้น) นี่อาจเป็นตัวอย่างบางอย่างที่พยายามดำเนินการอีกครั้งหรือเพื่อตั้งค่าเริ่มต้นแทน
หากไม่ใช่ในกรณีนี้ตัวอย่างเช่นเนื่องจากรหัสของเรามีโครงสร้างที่จะทำซ้ำจนกว่าจะสำเร็จแล้วเพียงแค่ผ่านก็ดีพอ จากตัวอย่างข้างต้นเราอาจต้องการให้ผู้ใช้ป้อนหมายเลข เนื่องจากเรารู้ว่าผู้ใช้ไม่ต้องการทำสิ่งที่เราขอพวกเราอาจจะใส่มันวนซ้ำในตอนแรกดังนั้นมันอาจเป็นแบบนี้
def askForNumber ():
while True:
try:
return int(input('Please enter a number: '))
except ValueError:
pass
เนื่องจากเราพยายามต่อไปจนกว่าจะไม่มีข้อยกเว้นเกิดขึ้นเราไม่จำเป็นต้องทำสิ่งใดเป็นพิเศษในบล็อกยกเว้นดังนั้นจึงไม่เป็นไร แต่แน่นอนเราอาจโต้แย้งว่าอย่างน้อยเราต้องการแสดงข้อความแสดงข้อผิดพลาดให้กับผู้ใช้เพื่อบอกเขาว่าเหตุใดเขาจึงต้องป้อนข้อมูลซ้ำ
ในอีกหลายกรณีแม้ว่าเพียงแค่ผ่านexcept
เป็นสัญญาณที่เราไม่ได้เตรียมไว้จริงๆสำหรับข้อยกเว้นที่เรากำลังจับ ยกเว้นว่าข้อยกเว้นนั้นง่าย (เช่นValueError
หรือTypeError
) และเหตุผลที่เราสามารถผ่านได้ชัดเจนพยายามหลีกเลี่ยงการเพิ่งผ่าน หากไม่มีอะไรให้ทำจริงๆ (และคุณแน่ใจจริงๆเกี่ยวกับเรื่องนี้) ให้ลองเพิ่มความคิดเห็นว่าทำไมถึงเป็นเช่นนั้น มิฉะนั้นให้ขยายบล็อกยกเว้นเพื่อรวมรหัสกู้คืนจริง ๆ
except: pass
ผู้กระทำความผิดที่เลวร้ายที่สุดคือการรวมกันของทั้งสอง ซึ่งหมายความว่าเรายินดีที่จะตรวจจับข้อผิดพลาดใด ๆแม้ว่าเราจะไม่ได้เตรียมอย่างแน่นอนและเราก็ไม่ได้ทำอะไรเกี่ยวกับเรื่องนี้ อย่างน้อยคุณต้องการบันทึกข้อผิดพลาดและมีแนวโน้มที่จะยังคงยกเลิกแอปพลิเคชัน (ไม่น่าเป็นไปได้ที่คุณจะสามารถดำเนินการต่อตามปกติหลังจาก MemoryError) การผ่านไปแม้ว่าจะไม่เพียงทำให้แอปพลิเคชันยังมีชีวิตอยู่ (ขึ้นอยู่กับตำแหน่งที่คุณติดตาม) แต่ยังทิ้งข้อมูลทั้งหมดทำให้ไม่สามารถค้นพบข้อผิดพลาด - ซึ่งเป็นจริงโดยเฉพาะอย่างยิ่งหากคุณไม่ใช่คนที่ค้นพบมัน
ดังนั้นกำไรคือจับข้อยกเว้นที่คุณคาดหวังและพร้อมที่จะกู้คืนจาก คนอื่น ๆ ทั้งหมดอาจเป็นความผิดพลาดที่คุณควรแก้ไขหรือสิ่งที่คุณไม่ได้เตรียมไว้ การผ่านข้อยกเว้นเฉพาะนั้นใช้ได้ถ้าคุณไม่จำเป็นต้องทำอะไรเกี่ยวกับพวกเขาจริงๆ ในกรณีอื่น ๆ ทั้งหมดมันเป็นเพียงสัญลักษณ์ของข้อสันนิษฐานและความขี้เกียจ และคุณต้องการแก้ไขอย่างแน่นอน
logging
โมดูลที่ระดับ DEBUG เพื่อหลีกเลี่ยงการสตรีมมิงค์ในการผลิต แต่ให้พร้อมในการพัฒนา