== สารบัญ ==
๛ ชนิดของข้อผิดพลาด
๛ การสร้างข้อผิดพลาดขึ้นมาเอง
๛ การสร้างคลาสของความผิดพลาด
๛ การปล่อยให้โปรแกรมดำเนินต่อเมื่อเจอข้อยกเว้น
๛ การจำกัดชนิดของความผิดพลาด
๛ การใช้ raise กับ try
๛ การเก็บข้อความเตือนข้อผิดพลาด
๛ try ซ้อน try
๛ การใช้ else กับ try และ except
๛ การใช้ finally
ข้อผิดพลาดในโปรแกรมแบ่งออกใหญ่ๆเป็น ๓ ชนิด ดังที่ได้กล่าวไปแล้วในบทที่ ๒ ได้แก่
- ข้อผิดพลาดทางวากยสัมพันธ์ (syntax error)
- ข้อผิดพลาดขณะการทำงาน (runtime error)
- ข้อผิดพลาดเชิงตรรกะ (logical error)
ในบทนี้จะพูดถึงข้อผิดพลาดขณะการทำงาน และการจัดการกับมัน
ปกติเวลาที่เจอข้อผิดพลาดแบบนี้โปรแกรมจะหยุดทำงานทันที โดยส่งข้อความมาบอกว่ามีการผิดพลาดอะไรเกิดขึ้น
ข้อผิดพลาดที่เกิดขึ้นนั้นมีหลากหลายชนิดมาก ซึ่งบอกให้รู้ว่ามีอะไรผิดพลาด เพื่อจะได้แก้ไขได้ถูกต้อง มีส่วนช่วยในการพัฒนาโปรแกรม
ชนิดของข้อผิดพลาด介 ในไพธอนข้อผิดพลาดถือเป็นคลาสรูปแบบหนึ่ง ชนิดของความผิดพลาดถูกแบ่งเป็นคลาสต่างๆ และมีการแตกคลาสย่อยออกไปด้วย ในที่นี้ขอยกตัวอย่างที่เจอบ่อย
NameError
เกิดขึ้นเวลาที่เรียกใช้ตัวแปรที่ไม่มีอยู่ มักเจอเวลาที่ตั้งใจจะใช้สายอักขระแต่ลืมใส่เครื่องหมายคำพูด
TypeError
เกิดขึ้นเวลาที่ใช้ออบเจ็กต์ผิดชนิด เช่นเวลาคำนวณแล้วเอาข้อมูลที่ไม่ควรจะบวกกันได้มาบวกกัน
ZeroDivisionError
เกิดขึ้นเวลาที่คำนวณแล้วมีการหาร 0
ValueError
เกิดขึ้นเมื่อใส่ค่าที่ไม่ควรจะใส่ลงไปในฟังก์ชัน
ModuleNotFoundError
เกิดขึ้นเมื่อใช้คำสั่ง
import
แล้วมีข้อผิดพลาด เช่นพิมพ์ชื่อมอดูลที่ไม่มีอยู่หรือยังไม่ได้ลงเอาไว้ หรือพิมพ์ชื่อผิด
IndexError
เกิดขึ้นเวลาที่อ้างอิงข้อมูลชนิดลำดับเช่นลิสต์, ทูเพิล, สายอักขระ แล้วใส่ดัชนีเกินจากค่าที่มีอยู่จริง
KeyError
เกิดขึ้นเวลาที่เรียกใช้ดิกชันนารีแล้วใส่คีย์ที่ไม่มีอยู่
FileNotFoundError
เกิดขึ้นเมื่อเวลาที่เปิดไฟล์แล้วไม่มีไฟล์นั้นอยู่
นอกจากนี้ก็ยังมีอีกมากมาย ถ้าได้เจอก็จะได้ทำความรู้จักกับมันเอง (แม้ว่าอาจจะไม่ได้อยากเจอก็ตาม)
ความผิดพลาดบางชนิดเป็นชนิดใกล้เคียงกัน มีซูเปอร์คลาสร่วมกัน เช่น
IndexError
กับ
KeyError
เป็นซับคลาสของ
LookupError
ความผิดพลาดทั้งหมดเป็นคลาสย่อยของคลาสที่ชื่อ
Exception
คลาสนี้เป็นคลาสรวมของความผิดพลาดพื้นฐานทุกชนิด
ความจริงแล้ว
Exception
ยังเป็นซับคลาสของคลาสที่ใหญ่กว่าคือ
BaseException
ซึ่งยังรวมความผิดพลาดที่นอกเหนือจากนี้ไป ซึ่งในที่นี้จะยังไม่พูดถึง
ได้
การสร้างข้อผิดพลาดขึ้นมาเอง介 ความผิดพลาดที่กระทบต่อการทำงานภายในโปรแกรมนั้นสามารถถูกตรวจจับและขึ้นเตือนได้ทั้งหมดดังที่ได้ยกตัวอย่างมาแล้ว
แต่นอกเหนือจากนั้นอาจมีความผิดพลาดที่เราไม่ต้องการ แต่โปรแกรมก็ทำงานไปตามปกติไม่ได้เตือนว่ามีการขัดข้องอะไร จัดเป็นข้อผิดพลาดเชิงตรรกะ
เช่นลองเขียนโปรแกรมง่ายๆที่คำนวณยอดเงินคงเหลือหลังกดตัง ซึ่งก็คือเงินในบัญชีลบด้วยเงินที่ถอนไป
ถ้าเงินที่ถอนน้อยกว่าเงินในบัญชีก็ไม่มีปัญหาอะไร แต่ถ้าเงินที่ถอนมากกว่าเมื่อไหร่ ก็จะได้เลขติดลบ เช่นใส่
12000
ก็จะได้ผลเป็น
-2000
ซึ่งในความเป็นจริงเป็นไปไม่ได้ที่จะถอนเงินเกิน
ดังนั้นเราต้องเขียนให้โปรแกรมรู้ด้วยว่าจะถอนเงินเกินแบบนี้ไม่ได้
โดยเราสามารถกำหนดสถานการณ์ที่จะให้โปรแกรมแสดงข้อผิดพลาดขึ้นมาได้เองโดยใช้คำ สั่ง
raise
โดยเขียน
raise
แล้วตามด้วยชนิดของความผิดพลาด วงเล็บด้วยข้อความที่จะขึ้นเตือน
ValueError
ในที่นี้คือชนิดของความผิดพลาดซึ่งเราสามารถกำหนดได้เอง ที่จริงจะกำหนดเป็นอะไรก็ได้ แต่ต้องเป็นชนิดที่เขากำหนดให้แต่แรก
ที่จริงแล้ว
ValueError
อาจไม่ค่อยถูกต้องนักที่จะใช้ในกรณีแบบนี้ ข้อผิดพลาดที่เราสร้างขึ้นเองส่วนใหญ่แล้วก็ไม่ได้ตรงกับรูปแบบที่มีให้อยู่แล้วแต่แรก
แต่เราสามารถสร้างรูปแบบความผิดพลาดขึ้นมาเองได้ด้วย ความผิดพลาดก็เป็นคลาสชนิดหนึ่ง คือเป็นคลาสย่อยของคลาส
Exception
การสร้างคลาสของความผิดพลาดขึ้นมาใหม่ก็คือสร้างคลาสโดยประกาศให้เป็นซับคลาสของ
Exception
การสร้างคลาสของความผิดพลาด介 คลาสของความผิดพลาดสามารถสร้างขึ้นมาได้ด้วยคำสั่ง
class
เหมือนกับคลาสทั่วไป โดยวงเล็บ
Exception
ไว้เป็นซูเปอร์คลาส หรือจะใช้ซูเปอร์คลาสเป็นข้อผิดพลาดชนิดอื่นก็ได้เช่นกัน
ตัวอย่าง สร้างคลาส
MonetaError
ขึ้นมาเตือนเวลาที่เงินไม่พอ
เมื่อป้อนตัวเลขเกิน 10000 เข้าไปจะได้ผลเป็น
เราอาจส่งค่าที่ขาดไปให้ไปแสดงในข้อความเตือนผิดพลาดด้วยได้ โดยใส่อาร์กิวเมนต์หลังชื่อคลาส แล้วตอนประกาศคลาสก็กำหนดส่วนที่ให้แสดงผลด้วย
เมื่อป้อนค่าเงินถอนไป 12000 ผลที่ได้คือ
การปล่อยให้โปรแกรมดำเนินต่อเมื่อเจอข้อยกเว้น介 ปกติถ้าเจอข้อผิดพลาดอะไรโปรแกรมจะหยุดทันที แต่ในบางครั้งมันก็เป็นความผิดพลาดที่เราคาดการณ์ได้อยู่แล้ว และไม่อยากให้โปรแกรมหยุดทำงานทันที แต่ให้โปรแกรมทำอะไรอย่างอื่นแทน
กรณีแบบนี้จะใช้คำสั่ง
try
และ
except
ตัวอย่าง เขียนโปรแกรมสำหรับอ่านไฟล์จากโปรแกรม
หากไฟล์ xxxx.txt ไม่มีตัวตนอยู่จะได้ว่า
หากเราไม่ต้องการให้เกิดความขัดข้องขึ้นแม้ว่าจะเปิดไฟล์ไม่สำเร็จก็อาจเขียนโดยใช้
try
และ
except
ดังนี้
ผลลัพธ์
จากตัวอย่างจะเห็นว่าเมื่อไฟล์เปิดไม่สำเร็จก็จะเกิดการกระทำคำสั่งที่อยู่ในโครงสร้าง
except
แต่หากเปิดไฟล์สำเร็จ เช่นลองรัน
แล้วค่อยรันโค้ดข้างต้นอีกทีจะได้ผลลัพธ์เป็น
โดยโค้ดส่วนที่อยู่ในโครงสร้าง
except
จะไม่ถูกอ่านเมื่อไม่มีการขัดข้องอะไรเกิดขึ้น
โครงสร้างของ
try
และ
except
นี้ว่าไปแล้วก็คล้าย
if
และ
else
แต่ต่างกันตรงที่ว่า
try
และ
except
ต้องอยู่คู่กันตลอด จะละ
except
ทิ้งไม่ได้
ถ้าไม่ต้องการให้มีการทำอะไรก็อาจแค่เติมเลข
0
หรืออาจใช้
pass
ก็ได้ เช่น
ผลลัพธ์
จะเห็นว่ามีการวนด้วย
for
ทั้งหมด ๗ ครั้ง แต่มีเลขออกมาแค่ ๖ ตัว เพราะเมื่อ
i
เท่ากับ
0
จะไม่เกิดอะไรขึ้น ถูกข้ามไปเลย
การจำกัดชนิดของความผิดพลาด介 ในส่วนของ
except
ถ้าเราเขียนแค่
except
เฉยๆก็จะมีการทำไม่ว่าจะเกิดความผิดพลาดแบบไหนก็ตาม แต่เราสามารถจำกัดเงื่อนไขของความผิดพลาดไปได้ด้วยการใส่ชนิดของความผิดพลาด ไว้ข้างหลัง
ลอง
โค้ดนี้ต่างจากตัวอย่างที่แล้วแค่เพิ่มคำว่า
ValueError
เข้ามาข้างหลัง
except
แต่ผลที่ได้ก็คือความผิดพลาดยังคงเกิดขึ้นมาตามปกติ
ที่เป็นแบบนี้ก็เนื่องจากว่าความผิดพลาดที่เกิดขึ้นนี้เป็นแบบ
FileNotFoundError
ไม่ใช่
ValueError
การเขียน
ValueError
ไว้ข้างหลัง
except
แบบนี้จะทำให้มันทำงานเฉพาะเมื่อมีข้อผิดพลาดแบบ
ValueError
เท่านั้น ดังนั้น
except
จึงไม่ทำงานในกรณีนี้
สามารถใช้
except
ที่มีเงื่อนไขต่างกันได้ในเวลาเดียวกัน
except
อันสุดท้ายอาจไม่ต้องเขียนชนิดลงไปก็ได้ ซึ่งมันจะทำงานเมื่อมีข้อผิดพลาดนอกเหนือจากที่ระบุข้างต้นมาแล้วทั้งหมด เช่น
การใช้ raise กับ try介 หากมีการใช้
raise
ในโครงสร้าง
try
ก็จะทำให้เกิดการทำอะไรใน
except
ได้เช่นกัน
คลาสของความผิดพลาดที่สร้างขึ้นมาเองก็สามารถนำมาใช้ได้เช่นกัน
การเก็บข้อความเตือนข้อผิดพลาด介 ปกติแล้วเวลาเกิดข้อผิดพลาดจะมีการสร้างออบเจ็กต์ที่เป็นอินสแตนซ์ของคลาสความผิดพลาดนั้นขึ้น
ออบเจ็กต์นั้นเป็นตัวกำหนดข้อความที่แสดงออกมาเมื่อมีความผิดพลาดเกิดขึ้น โดยจะต่างกันออกไปตามคลาสของความผิดพลาด
แต่ถ้าหากใช้
try
และ
except
แล้วเกิดข้อผิดพลาดขึ้นใน
try
จะไม่มีการแสดงข้อความที่เตือนถึงข้อผิดพลาด แต่จะทำเหมือนไม่มีอะไรเกิดขึ้นเลย
แต่หากต้องการเก็บออบเจ็กต์ที่เกิดจากความผิดพลาดนั้นไว้เพื่อแสดงผลก็สามารถทำได้ โดยเพิ่มคำว่า
as
ไปด้านหลังชนิดของข้อผิดพลาดซึ่งตามหลัง
except
อีกที แล้วหลัง
as
ใส่ตัวแปรที่ต้องการให้มารับออบเจ็กต์ของความผิดพลาด
ในตัวอย่างนี้ตัวแปร
er
จะเก็บออบเจ็กต์ของความผิดพลาดเอาไว้ พอใช้
type
ก็จะแสดงคลาสของความผิดพลาด ในที่นี้คือ
ValueError
เมื่อใช้
print
กับออบเจ็กต์ของความผิดพลาดจะเป็นการแสดงข้อความเตือนที่ผิดพลาด
***ในไพธอน ๒ จะมีวิธีการเขียนต่างออกไป โดยใช้จุลภาค
,
แทน
as
>>> รายละเอียด try ซ้อน try介 โครงสร้าง
try
สามารถใช้ซ้อนกันได้ เช่น
จะได้
จะเห็นว่าพอมีข้อผิดพลาดอยู่ภายในจะมีการทำในสิ่งที่อยู่ในโครงสร้าง
except
ด้านใน แต่มันก็ทำให้โปรแกรมทำงานต่อไปตามปกติ ดังนั้น
except
ด้านนอกก็จะถูกมองข้ามไป
หากต้องการให้เวลามีข้อผิดพลาดข้างในแล้วมีการทำ
except
ข้างนอกด้วยก็อาจจะใส่
raise
ภายใน
except
ด้านในอีกที
ได้
การใช้ else กับ try และ except介 โครงสร้าง
try
except
สามารถต่อด้วย
else
ได้ด้วย โดยจะตรงข้ามกับ
except
คือเป็นคำสั่งที่จะทำเมื่อไม่มีการขัดข้องเกิดขึ้นเท่านั้น
ลองดูตัวอย่าง กรณีที่มีข้อผิดพลาด
ผลลัพธ์
เทียบกับกรณีที่ทำงานตามปกติไม่มีข้อผิดพลาด
ผลลัพธ์
การใช้ finally介 ในการจัดการกับข้อยกเว้นนอกจาก
try
,
except
และ
else
แล้วยังมี
finally
ซึ่งใช้น้อยกว่า จึงขอแยกไปเขียนเป็นเนื้อหาเสริมในอีกหน้า
>> การใช้ finally ร่วมกับ try และ except ในการจัดการข้อยกเว้น อ้างอิง