มาใช้งานการจัดการ Exception ใน Python (try-except) ให้เชี่ยวชาญกันเถอะ
หากต้องการเรียกใช้ Python ผ่าน Command Prompt หรือ PowerShell บนคอมพิวเตอร์ของคุณ คุณจำเป็นต้องดาวน์โหลดและติดตั้ง Python ก่อน
หากคุณยังไม่ได้ติดตั้ง กรุณาดูบทความ การติดตั้ง Python และการตั้งค่าสภาพแวดล้อมการพัฒนา เพื่อทำการติดตั้ง Python
ในการเขียนโปรแกรม เป็นเรื่องที่หลีกเลี่ยงไม่ได้ที่จะต้องเจอกับข้อผิดพลาดที่ไม่คาดคิด สาเหตุของข้อผิดพลาดมีได้หลากหลาย เช่น การป้อนข้อมูลที่ผิดพลาดของผู้ใช้, การไม่มีอยู่ของไฟล์, หรือปัญหาเกี่ยวกับเครือข่าย ในสถานการณ์เช่นนี้ "การจัดการ Exception" คือกลไกที่จะช่วยป้องกันไม่ให้โปรแกรมหยุดทำงานกะทันหัน และช่วยให้สามารถรับมือกับปัญหาได้อย่างชาญฉลาด
ในบทความนี้ เราจะอธิบายตั้งแต่พื้นฐานไปจนถึงการประยุกต์ใช้การจัดการ Exception ด้วยคำสั่ง try-except ของ Python พร้อมตัวอย่างโค้ดที่สามารถคัดลอกไปใช้งานได้ทันที เพื่อให้ผู้เริ่มต้นสามารถเข้าใจได้ง่าย มาเรียนรู้วิธีการสร้างโปรแกรมที่ทนทานต่อข้อผิดพลาดไปพร้อมๆ กับการได้สัมผัสประสบการณ์ "โค้ดที่ทำงานได้จริง" กันเถอะ!
เริ่มต้นจากพื้นฐาน! โครงสร้าง try-except
รูปแบบพื้นฐานที่สุดของการจัดการ Exception คือคำสั่ง try-except ซึ่งตามชื่อของมันเลย คือการสร้างขั้นตอนการทำงานแบบ "try (ลองทำดู) และถ้าหากเกิด Exception (ข้อผิดพลาด) ขึ้นมา ก็ให้ except (ดักจับและจัดการ)"
โครงสร้างของมันเรียบง่ายมาก:
- ในบล็อก
tryให้ใส่โค้ดที่อาจเกิดข้อผิดพลาดได้ - ในบล็อก
exceptให้ใส่โค้ดที่ต้องการให้ทำงานเมื่อเกิดข้อผิดพลาด
สิบปากว่าไม่เท่าตาเห็น เรามาดูตัวอย่างจากข้อผิดพลาดที่รู้จักกันดีอย่าง "การหารด้วยศูนย์" (ZeroDivisionError) กันดีกว่า ในโค้ดด้านล่างนี้ เราพยายามจะหาร 10 ด้วย 0 ซึ่งโดยปกติแล้วจะทำให้โปรแกรมหยุดทำงานเพราะเกิดข้อผิดพลาด แต่เราสามารถใช้ try-except เพื่อดักจับมันไว้ได้
<!-- โค้ด Python -->
try:
# โค้ดที่อาจเกิดข้อผิดพลาด
result = 10 / 0
print(f"ผลการคำนวณ: {result}")
except ZeroDivisionError:
# การทำงานเมื่อเกิด ZeroDivisionError
print("อุ๊ปส์! ไม่สามารถหารด้วย 0 ได้")
print("โปรแกรมทำงานเสร็จสิ้นอย่างถูกต้อง")
การดักจับ Exception ที่เจาะจง! ด้วย except หลายตัว
ในโปรแกรม อาจเกิดข้อผิดพลาดได้หลายประเภท ตัวอย่างเช่น ในการรับข้อมูลจากผู้ใช้ อาจเกิดกรณี "ต้องการให้ป้อนตัวเลข แต่กลับได้รับข้อความ" (ValueError) หรือในการจัดการไฟล์ อาจเกิดกรณี "ไม่พบไฟล์ที่ระบุ" (FileNotFoundError)
การระบุประเภทของข้อผิดพลาด (Exception class) ต่อท้ายคำสั่ง except จะทำให้เราสามารถดักจับเฉพาะข้อผิดพลาดที่เจาะจง และดำเนินการจัดการที่เหมาะสมกับแต่ละประเภทได้
นอกจากนี้ เรายังสามารถเขียน except หลายๆ บล็อกเรียงต่อกัน เพื่อแยกการจัดการตามประเภทของข้อผิดพลาดได้อีกด้วย ในตัวอย่างด้านล่างนี้ เราจะพยายามแปลงข้อความให้เป็นจำนวนเต็ม
<!-- โค้ด Python -->
user_input = "hello" # ไม่ใช่ตัวเลข แต่เป็นข้อความ
try:
num = int(user_input)
print(f"ตัวเลขที่ป้อน: {num}")
except ValueError:
print("กรุณาป้อนเป็นตัวเลข! ข้อความไม่สามารถแปลงเป็นตัวเลขได้")
except TypeError:
print("ประเภทข้อมูลไม่ถูกต้อง! ไม่ใช่ประเภทที่สามารถแปลงเป็นตัวเลขได้")
print("ดำเนินการต่อไป...")
ในหลายกรณี เราก็อยากจะทราบข้อมูลรายละเอียด (ข้อความของข้อผิดพลาด) ของ Exception ที่เกิดขึ้น ในกรณีเช่นนี้ เราสามารถใช้ as เพื่อเก็บอ็อบเจกต์ของ Exception ไว้ในตัวแปรได้ โดยทั่วไปแล้ว มักจะใช้ชื่อตัวแปรว่า e (ซึ่งย่อมาจาก error หรือ exception)
<!-- โค้ด Python -->
try:
# พยายามเปิดไฟล์ที่ไม่มีอยู่จริง
with open("ไฟล์ที่ไม่มีอยู่.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
# แสดงรายละเอียดของข้อผิดพลาด
print(f"ไม่พบไฟล์ดังกล่าว")
print(f"รายละเอียดข้อผิดพลาด: {e}")
การประยุกต์ใช้: การใช้งาน else และ finally ให้เกิดประโยชน์สูงสุด
ใน try-except ยังมีส่วนเสริมที่ทรงพลังอีกสองอย่างคือ else และ finally การผสมผสานสิ่งเหล่านี้เข้าด้วยกัน จะทำให้สามารถจัดการกับสถานการณ์ต่างๆ ได้อย่างละเอียดมากยิ่งขึ้น
- บล็อก else: จะทำงานก็ต่อเมื่อในบล็อก
tryไม่เกิด Exception ใดๆ ขึ้นเลย มีประโยชน์เมื่อต้องการแยกโค้ดที่ทำงานในกรณีปกติออกจากส่วนที่จัดการข้อผิดพลาดอย่างชัดเจน - บล็อก finally: จะทำงานเป็นส่วนสุดท้ายเสมอ ไม่ว่าจะเกิด Exception หรือไม่ก็ตาม เหมาะอย่างยิ่งสำหรับการเขียนโค้ดเพื่อ "เก็บกวาด" เช่น การปิดไฟล์หรือการปิดการเชื่อมต่อเน็ตเวิร์ก
เรามาดูโค้ดที่ใช้ทุกองค์ประกอบเหล่านี้กัน
<!-- โค้ด Python -->
file_path = "my_data.txt"
data_to_write = "นี่คือข้อมูลทดสอบ"
try:
print(f"กำลังเขียนข้อมูลลงใน '{file_path}'...")
f = open(file_path, "w", encoding="utf-8")
# หากต้องการทำให้เกิดข้อผิดพลาดโดยเจตนา ให้ลบเครื่องหมาย # หน้าบรรทัดถัดไป
# f.write(12345) # การพยายามเขียนข้อมูลที่ไม่ใช่ข้อความจะทำให้เกิด TypeError
f.write(data_to_write)
print("ได้พยายามทำการเขียนแล้ว")
except TypeError as e:
print(f"เกิดข้อผิดพลาด! ข้อมูลที่จะเขียนต้องเป็นข้อความเท่านั้น")
print(f"รายละเอียดข้อผิดพลาด: {e}")
except Exception as e:
# ดักจับข้อผิดพลาดอื่นๆ ที่ไม่คาดคิด
print(f"เกิดข้อผิดพลาดที่ไม่คาดคิด")
print(f"รายละเอียดข้อผิดพลาด: {e}")
else:
# ทำงานเมื่อไม่เกิด Exception ในบล็อก try
print("การเขียนข้อมูลลงไฟล์สำเร็จ!")
finally:
# ทำงานเสมอ ไม่ว่าจะเกิด Exception หรือไม่
if 'f' in locals() and not f.closed:
f.close()
print("ได้ทำการปิดไฟล์แล้ว")
else:
print("ไฟล์ไม่ได้ถูกเปิดหรือถูกปิดไปแล้ว")
print("--- การประมวลผลเสร็จสิ้น ---")
ภาคปฏิบัติ! ตัวอย่างโค้ดฉบับสมบูรณ์ที่ก๊อปปี้ไปรันได้เลย
ทีนี้ เราลองมารวบรวมความรู้ทั้งหมดที่ได้เรียนมาเพื่อสร้างโปรแกรมที่ใช้งานได้จริงกันดูบ้าง โค้ดนี้จะทำการถามอายุจากผู้ใช้ และจะวนซ้ำเพื่อขอข้อมูลไปเรื่อยๆ จนกว่าจะได้รับค่าที่เป็นตัวเลขที่ถูกต้อง จากนั้นจะทำการบันทึกอายุที่ได้รับลงในไฟล์ โดยข้อผิดพลาดที่อาจเกิดขึ้นระหว่างทางจะถูกจัดการด้วย try-except
ให้คัดลอกโค้ดทั้งหมดด้านล่างนี้ไปวางในไฟล์ที่ชื่อว่า age_logger.py แล้วลองรันในเทอร์มินัลด้วยคำสั่ง python age_logger.py ดูสิ ลองป้อนข้อมูลที่เป็นตัวอักษรเพื่อดูว่าการจัดการข้อผิดพลาดทำงานอย่างไร!
<!-- สคริปต์ Python ทั้งหมด: age_logger.py -->
import datetime
def record_age():
"""
ฟังก์ชันสำหรับถามอายุจากผู้ใช้และบันทึกลงไฟล์
มีการตรวจสอบความถูกต้องของข้อมูลและจัดการข้อผิดพลาดเกี่ยวกับไฟล์ I/O
"""
while True:
try:
# รับข้อมูลจากผู้ใช้
age_str = input("กรุณาป้อนอายุของคุณเป็นตัวเลข: ")
# แปลงข้อความเป็นจำนวนเต็ม
age = int(age_str)
# ตรวจสอบค่าติดลบหรืออายุที่ไม่สมจริง
if age < 0 or age > 130:
# สร้างข้อผิดพลาดขึ้นมาเอง (raise)
raise ValueError("กรุณาป้อนอายุระหว่าง 0 ถึง 130 ปี")
# หากป้อนอายุที่ถูกต้องแล้ว ให้ออกจากลูป
break
except ValueError as e:
# ดักจับข้อผิดพลาดจากการแปลง int() หรือ ValueError ที่เราสร้างขึ้น
print(f"ข้อผิดพลาด: {e}")
print("กรุณาลองใหม่อีกครั้งด้วยตัวเลขที่ถูกต้อง\n")
# บันทึกลงไฟล์
try:
# การใช้ with จะทำให้ไฟล์ถูกปิดโดยอัตโนมัติ ไม่จำเป็นต้องใช้ finally เพื่อ close()
with open("age_log.txt", "a", encoding="utf-8") as f:
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(f"[{timestamp}] อายุที่บันทึก: {age} ปี\n")
print(f"บันทึกอายุของคุณ '{age} ปี' ลงใน 'age_log.txt' เรียบร้อยแล้ว")
except IOError as e:
# ดักจับข้อผิดพลาดเช่น ไม่มีสิทธิ์ในการเขียนไฟล์
print("ข้อผิดพลาดร้ายแรง: ไม่สามารถเขียนข้อมูลลงไฟล์ได้")
print(f"รายละเอียดข้อผิดพลาด: {e}")
if __name__ == "__main__":
record_age()
print("ขอบคุณที่ใช้บริการ")
ข้อควรระวัง: การดักจับ Exception ในขอบเขตที่กว้างเกินไป
การจัดการ Exception นั้นมีประโยชน์ แต่หากใช้ไม่ถูกวิธี ก็อาจทำให้การค้นหาปัญหาในโปรแกรมทำได้ยากขึ้น สิ่งที่ต้องระวังเป็นพิเศษคือการดักจับ Exception ในขอบเขตที่กว้างเกินไป
สิ่งที่ไม่แนะนำ: การใช้ except แบบเปล่าๆ
การเขียนที่แย่ที่สุดคือการใช้ except: แบบ "เปล่าๆ" โดยไม่ระบุประเภทของ Exception เพราะมันจะดักจับข้อผิดพลาดทุกอย่างโดยไม่เลือกหน้า ซึ่งรวมไปถึง SystemExit ที่ใช้ในการจบการทำงานของโปรแกรม หรือแม้กระทั่ง KeyboardInterrupt ที่เกิดจากการกด Ctrl+C เพื่อบังคับหยุดโปรแกรม ซึ่งอาจนำไปสู่สถานการณ์ที่อยากจะหยุดโปรแกรมแต่ก็หยุดไม่ได้
สิ่งที่ต้องระวัง: การใช้ except Exception
except Exception as e: นั้นดีกว่าการใช้ except: แบบเปล่าๆ แต่ก็ยังคงดักจับข้อผิดพลาดทั่วไปส่วนใหญ่ได้อยู่ดี ในระหว่างการพัฒนา หลายครั้งเราต้องการให้เกิดข้อผิดพลาดเพื่อที่จะได้ค้นเจอบั๊กที่ไม่คาดคิด การดักจับทุกอย่างโดยไม่เลือกอาจทำให้บั๊กที่ควรจะได้รับการแก้ไขถูกซ่อนเอาไว้
แนวทางปฏิบัติที่ดีที่สุดคือ "การระบุและดักจับเฉพาะ Exception ที่เราคาดการณ์ได้และสามารถจัดการได้อย่างเหมาะสมเท่านั้น"
สรุปและขั้นตอนต่อไป
ในครั้งนี้ เราได้เรียนรู้เกี่ยวกับคำสั่ง try-except ของ Python สำหรับการจัดการ Exception เรามาทบทวนประเด็นสำคัญกัน
try-exceptช่วยป้องกันไม่ให้โปรแกรมหยุดทำงานเนื่องจากข้อผิดพลาดexcept ExceptionClass as eช่วยให้สามารถดักจับข้อผิดพลาดที่เจาะจงและรับข้อมูลรายละเอียดได้elseใช้สำหรับโค้ดที่ทำงานเมื่อสำเร็จ และfinallyใช้สำหรับงานเก็บกวาด- เคล็ดลับคือการจำกัดการดักจับ Exception ให้แคบลงเหลือเฉพาะกรณีที่เจาะจงและสามารถจัดการได้
เมื่อคุณเชี่ยวชาญการจัดการ Exception แล้ว คุณจะสามารถสร้างแอปพลิเคชันที่แข็งแกร่ง เป็นมิตรกับผู้ใช้ และง่ายต่อการบำรุงรักษาสำหรับนักพัฒนา ลองนำ try-except ไปใช้ในโค้ดของคุณดูสิ
สำหรับขั้นตอนต่อไป ทำไมไม่ลองเรียนรู้เกี่ยวกับแนวคิดที่สำคัญสำหรับการสร้างโปรแกรมให้เป็นสัดส่วนและเพิ่มความสามารถในการนำกลับมาใช้ใหม่ดูล่ะ?
>> บทความถัดไป: ความรู้เบื้องต้นเกี่ยวกับคลาสและการเขียนโปรแกรมเชิงวัตถุใน Python