ข้ามไปยังเนื้อหา

Exceptions

Exception คือสัญญาณที่บอกว่ามีบางอย่างผิดพลาดระหว่างการรัน เมื่อ Python raise exception จะ unwind call stack จนกว่าจะเจอ except clause ที่ตรงกัน หรือหยุดโปรแกรม

Exception คือ object — instance ของ class ที่สืบทอดจาก BaseException Exception ที่ใช้งานในโค้ดทั่วไปมักสืบทอดจาก Exception

try:
result = risky_operation()
except SomeError as e:
# ทำงานเฉพาะเมื่อ SomeError (หรือ subclass) ถูก raise
handle(e)
else:
# ทำงานเฉพาะเมื่อไม่มี exception เกิดขึ้นใน try
use(result)
finally:
# ทำงานเสมอ — ไม่ว่าจะเกิด exception หรือไม่
cleanup()

Block else เป็น feature Python ที่มีประโยชน์: ช่วยแยกแยะ “การดำเนินการสำเร็จ” ออกจาก “เราอยู่ใน cleanup” โค้ดใน else ทำงานเฉพาะเส้นทาง happy path เท่านั้น

จับ exception ที่เฉพาะเจาะจงที่สุดเสมอ การจับ Exception เป็นทางเลือกสุดท้าย ส่วน except: เปล่าจะกลืน KeyboardInterrupt และ SystemExit ไปด้วย

try:
n = int(user_input)
except ValueError:
print("Not a valid integer")
except TypeError:
print("Expected a string, not None")

จับหลายประเภทในบรรทัดเดียวด้วย tuple:

except (ValueError, TypeError) as e:
print(f"Input error: {e}")

ใช้ raise เพื่อส่งสัญญาณ error อย่างชัดเจน:

def divide(a: float, b: float) -> float:
if b == 0:
raise ValueError("divisor cannot be zero")
return a / b

Re-raise exception ปัจจุบันภายใน except block ด้วย raise เปล่า:

except ValueError:
log_error()
raise # re-raise exception เดิมโดยไม่เปลี่ยนแปลง

เมื่อจับ exception หนึ่งแล้ว raise อีกอัน ให้ใช้ raise NewError(...) from original เพื่อเก็บ exception เดิมไว้เป็นสาเหตุ ทำให้ traceback ครบถ้วน

try:
value = int(raw_string)
except ValueError as original:
raise RuntimeError("Failed to parse config") from original

Attribute __cause__ บน exception ใหม่เก็บ exception เดิมไว้ Python แสดง traceback ทั้งสองอันอัตโนมัติ

หากต้องการตัด chain (ซ่อน traceback เดิม) ใช้ raise ... from None

def safe_divide(a: float, b: float) -> float:
"""Divide a by b, raising ValueError if b is zero."""
if b == 0:
raise ValueError("divisor cannot be zero")
return a / b
# --- try / except / else / finally ---
print("=== basic try/except/else/finally ===")
for b in [2.0, 0]:
try:
result = safe_divide(10.0, b)
except ValueError as e:
print(f" ValueError: {e}")
else:
print(f" Result: {result}")
finally:
print(" finally ran")
# --- catching specific types ---
print("\n=== specific exception types ===")
for val in ["42", "abc", None]:
try:
n = int(val)
print(f" parsed {val!r} -> {n}")
except (TypeError, ValueError) as e:
print(f" {type(e).__name__} for {val!r}: {e}")
# --- exception chaining ---
print("\n=== exception chaining ===")
try:
try:
raw = "not-a-number"
value = int(raw)
except ValueError as original:
raise RuntimeError("Failed to parse config value") from original
except RuntimeError as e:
print(f" RuntimeError: {e}")
print(f" __cause__: {e.__cause__}")
Block `else` ใน try statement ทำงานเมื่อใด?
`raise RuntimeError('msg') from original` ทำอะไร?
Clause ใดใน try statement ทำงานเสมอ แม้จะเกิด exception?
ปัญหาของ `except:` เปล่า (ไม่ระบุประเภท exception) คืออะไร?