2.25. การจัดการข้อผิดพลาด¶
ปัญหา runtime ส่วนใหญ่ใน Python แสดงออกมาเป็น exceptions ซึ่งเป็นวิธีรายงานที่มีชื่อและโครงสร้างว่ามีบางอย่างผิดพลาด ValueError, TypeError, KeyError, OSError, MemoryError เป็นตัวอย่างทั้งหมด แต่ละอันเป็น class และการ raise หนึ่งอันจะหยุดการเรียกปัจจุบันและค้นหา handler ในโค้ดโดยรอบ
2.25.1. try / except¶
ครอบบล็อกโค้ดด้วย try เพื่อดักจับ exception ที่เกิดขึ้น:
try:
n = int(input_text)
except ValueError:
n = 0
หากการแปลง int(...) ล้มเหลว การควบคุมจะกระโดดไปยังบล็อก except แทนที่จะส่งต่อข้อผิดพลาด หาก input_text เป็น string จำนวนเต็มที่ถูกต้อง บล็อก except จะถูกข้าม
try เดียวสามารถมีบล็อก except หลายบล็อก แต่ละบล็อกดักจับข้อผิดพลาดประเภทต่างกัน:
try:
value = data[key]
except KeyError:
value = None
except TypeError:
value = -1
Python จับคู่ตามลำดับ อันแรกที่ class exception ตรงกันจะจัดการปัญหา การดักจับ Exception (base class สำหรับเกือบทุกอย่าง) จัดการ ข้อผิดพลาดใดก็ได้ สงวนไว้สำหรับชั้นนอกสุดของโปรแกรมที่ทางเลือกคือการ crash
Warning
except: แบบเปล่า (ไม่มี class หลัง keyword) ยังดักจับ KeyboardInterrupt ด้วย ซึ่งเป็น exception ที่ IDE ส่งเมื่อคุณกดปุ่ม stop เพื่อหยุดสคริปต์ที่กำลังทำงาน ลูปที่ครอบด้วย except: pass แบบเปล่าจะกลืน interrupt และทำงานต่อ ทำให้ไม่มีทางหยุดสคริปต์ได้ยกเว้นการรีบูต
เลือกใช้ except Exception: แทน except: แบบเปล่าเมื่อต้องการดักจับในวงกว้างจริงๆ KeyboardInterrupt สืบทอดจาก BaseException ไม่ใช่ Exception ดังนั้น except Exception: จะยังคงให้ปุ่ม stop ทำงานได้
2.25.1.1. การตรวจสอบ exception¶
หากต้องการอ่านข้อความที่แนบมากับ exception ให้ตั้งชื่อด้วย as:
try:
f = open("data.txt")
except OSError as e:
print("could not open file:", e)
ตัวแปรที่ผูกด้วย as ใช้ได้เฉพาะภายในบล็อก except เท่านั้น
2.25.2. else และ finally¶
บล็อก try มี extras แบบไม่บังคับสองอย่าง
else ทำงานเฉพาะเมื่อ try เสร็จสิ้นโดยไม่มีการ raise:
try:
value = compute()
except ValueError:
print("bad input")
else:
print("got", value)
การวาง "สิ่งที่ต้องทำเมื่อสำเร็จ" ไว้ใน else ทำให้บล็อก try แคบลง มีเพียงบรรทัดที่อาจล้มเหลวเท่านั้นที่อยู่ใน try
finally ทำงานตอนท้าย ไม่ว่าจะเกิดอะไร ไม่ว่า try จะสำเร็จ ถูก raise และจัดการแล้ว หรือถูก raise และกำลังจะส่งต่อ:
try:
do_work()
finally:
cleanup()
finally ทำงานเสมอ else ทำงานเฉพาะในเส้นทางที่ไม่มี exception¶
สำหรับ pattern การ acquire/release ส่วนใหญ่ เลือกใช้ context manager แทนคู่ try / finally เพราะ resource จัดการ cleanup ของตัวเองได้
2.25.3. Built-in exceptions ที่พบบ่อย¶
รายการสั้นๆ ของ exceptions ที่คุณจะพบบ่อย:
ValueError-- ประเภทถูกต้อง ค่าไม่ถูกต้อง (bytes([300])-- 300 เป็นประเภทที่ถูกต้อง แต่อยู่นอกช่วง byte ที่ถูกต้อง 0..255)TypeError-- ประเภทผิดทั้งหมด (len(42))IndexError-- index เกินขอบเขตของลำดับAttributeError-- เข้าถึง attribute ที่ไม่มีอยู่ ("abc".foo)OSError-- ความล้มเหลวของ filesystem หรือ I/OMemoryError-- heap หมด บน runtime ที่มีหน่วยความจำจำกัด สิ่งนี้อาจเกิดขึ้นระหว่างการทำงานปกติ ไม่ใช่แค่ในกรณีสุดขีด