จับข้อยกเว้นด้วย Try ยกเว้นใน Python

โปรแกรม Python ล้มเหลวในขณะรันไทม์เมื่อการดำเนินการเช่นการเข้าถึงไฟล์ การแยกวิเคราะห์อินพุต หรือการเรียกเครือข่ายทำให้เกิดข้อยกเว้น จัดการกับสิ่งเหล่านี้ด้วยtry/exceptช่วยให้แอปของคุณตอบสนอง รักษาบริบทที่เป็นประโยชน์ และรับประกันการล้างข้อมูล

ก่อนที่คุณจะเริ่ม — กฎหลัก

  • จับประเภทข้อยกเว้นที่เฉพาะเจาะจงที่สุดที่คุณคาดหวัง (เช่นValueError,FileNotFoundError) ไม่ใช่สิ่งที่ครอบคลุมทั้งหมด
  • ใช้elseเพื่อเส้นทางแห่งความสำเร็จและfinallyสำหรับโค้ดที่ต้องรันไม่ว่าจะยังไงก็ตาม
  • ต้องการตัวจัดการบริบท (with) สำหรับไฟล์และทรัพยากรอื่นๆ เพื่อให้การล้างข้อมูลง่ายขึ้น
  • ปล่อยให้ข้อผิดพลาดที่ไม่คาดคิดแพร่กระจาย บันทึกพวกมันแล้วเลี้ยงใหม่แทนที่จะกลืนพวกมันไปอย่างเงียบ ๆ
  • ตัวจัดการที่รับทั้งหมดสำรอง (except Exceptionหรือexcept BaseException) สำหรับขอบเขตระดับบนสุดที่คุณสามารถล้มเหลวได้อย่างรวดเร็วหรือรายงานได้อย่างชัดเจน

ขั้นตอนที่ 1:ระบุการดำเนินการที่มีความเสี่ยงหนึ่งรายการเพื่อปกป้อง

raw = input("Select a fruit number (0-2): ")

ขั้นตอนที่ 2:ห่อการดำเนินการเข้าไว้try/exceptและจัดการประเภทข้อยกเว้นที่ชัดเจน

try:
    selection = ["apple", "pear", "banana"][int(raw)]
    print("You chose:", selection)
except ValueError:
    print("Not a number.")
except IndexError:
    print("Choice out of range.")

ขั้นตอนที่ 3:จัดกลุ่มข้อยกเว้นที่เกี่ยวข้องเมื่อการกู้คืนเหมือนกัน

try:
    selection = ["apple", "pear", "banana"][int(raw)]
except (ValueError, IndexError) as e:
    print("Invalid selection:", type(e).__name__)

ข้อยกเว้นเฉพาะทั่วไป ได้แก่OSErrorครอบครัว (ไฟล์)ValueErrorและTypeError(ข้อมูล),ZeroDivisionError(คณิตศาสตร์) และKeyError/IndexError(คอลเลกชัน)

วิธีที่ 2 — ใช้ else และสุดท้ายเพื่อแยกความสำเร็จและการล้างข้อมูล

ขั้นตอนที่ 1:เพิ่มelseสำหรับโค้ดที่ควรจะรันก็ต่อเมื่อไม่มีอะไรล้มเหลว

try:
    f = open("config.json", "r", encoding="utf-8")
except FileNotFoundError:
    print("No config file found.")
else:
    data = f.read()
    print("Loaded", len(data), "bytes.")
    f.close()

ขั้นตอนที่ 2:เพิ่มfinallyสำหรับการล้างข้อมูลที่จะต้องเกิดขึ้นไม่ว่าการลองจะสำเร็จหรือไม่ก็ตาม

f = None
try:
    f = open("config.json", "r", encoding="utf-8")
    data = f.read()
except OSError as err:
    print("OS error:", err)
finally:
    if f:
        f.close()

วิธีที่ 3 — ป้องกันจุดเริ่มต้นของคุณให้ล้มเหลวอย่างรวดเร็วและบันทึก

ขั้นตอนที่ 1:ย้ายขั้นตอนการทำงานของคุณไปที่main()การทำงาน.

def main():
    # core workflow
    # ...
    return 0

ขั้นตอนที่ 2:ตัดสายในระดับบนสุดtry/exceptเพื่อบันทึกข้อผิดพลาดที่ไม่คาดคิดและหยุดโปรแกรม

import logging, sys

logging.basicConfig(level=logging.INFO)

if __name__ == "__main__":
    try:
        code = main()
    except Exception:
        logging.exception("Unhandled error")
        sys.exit(1)
    sys.exit(code)

ขั้นตอนที่ 3:ส่งคืนโค้ดทางออกที่ไม่ใช่ศูนย์เมื่อล้มเหลวในการส่งสัญญาณให้เครื่องมืออัตโนมัติทราบว่าการทำงานล้มเหลว

# in main(), return 1 or raise an exception when a critical step fails

วิธีที่ 4 — จัดการทรัพยากรด้วยwith(เป็นที่ต้องการมากกว่าคู่มือในที่สุด)

ขั้นตอนที่ 1:แทนที่การเปิด/ปิดด้วยตนเองด้วยตัวจัดการบริบทเพื่อบังคับใช้การเปิดตัวในเวลาที่เหมาะสม

from pathlib import Path

try:
    with Path("data.txt").open("r", encoding="utf-8") as f:
        print(f.readline().strip())
except FileNotFoundError:
    print("Create data.txt first.")

ขั้นตอนที่ 2:เก็บเฉพาะการดำเนินการที่มีความเสี่ยงไว้ในบล็อกที่ได้รับการป้องกันเพื่อหลีกเลี่ยงข้อผิดพลาดที่ไม่เกี่ยวข้อง

try:
    with open("image.png", "rb") as fh:
        blob = fh.read()
except OSError as e:
    print("File access failed:", e)
# decode/process blob in a separate block

วิธีที่ 5 — Raise, re-raise และ chain ข้อยกเว้นสำหรับเส้นทางข้อผิดพลาดที่ชัดเจน

ขั้นตอนที่ 1:ยกข้อยกเว้นเฉพาะเมื่อเงื่อนไขเบื้องต้นล้มเหลว

def parse_age(s: str) -> int:
    if not s.isdigit():
        raise ValueError("age must contain only digits")
    age = int(s)
    if age < 0:
        raise ValueError("age cannot be negative")
    return age

ขั้นตอนที่ 2:แจ้งข้อผิดพลาดที่ไม่คาดคิดอีกครั้งหลังจากบันทึก เพื่อให้ผู้โทรสามารถจัดการข้อผิดพลาดเหล่านั้นได้

import logging

try:
    do_risky_thing()
except OSError as err:
    logging.error("OS error: %s", err)
    raise

ขั้นตอนที่ 3:ข้อยกเว้นลูกโซ่ด้วยraise ... from eเพื่อรักษาต้นเหตุในขณะที่เพิ่มบริบท

ดูเพิ่มเติมที่:

from pathlib import Path
import json

def load_json(path: str):
    try:
        text = Path(path).read_text(encoding="utf-8")
    except OSError as e:
        raise RuntimeError(f"Failed to read {path}") from e
    return json.loads(text)

วิธีที่ 6 — การจัดการแบบ Catch-all ที่ขอบเขต (ใช้เท่าที่จำเป็น)

ขั้นตอนที่ 1:ใช้except Exception as eเพื่อบันทึกข้อผิดพลาดที่ไม่ได้ออกจากระบบ บันทึกรายละเอียด และตัดสินใจว่าจะหยุดหรือลองอีกครั้ง

import traceback

try:
    risky()
except Exception as e:
    print(f"Unexpected {type(e).__name__}: {e}")
    traceback.print_exc()  # full stack trace
    # decide: raise, return error, or abort

ขั้นตอนที่ 2:จับเท่านั้นBaseExceptionหากคุณจงใจสกัดกั้นKeyboardInterruptหรือSystemExitแล้วขึ้นใหม่ทันที

try:
    service_loop()
except BaseException as e:
    print(f"Caught {type(e).__name__}; shutting down cleanly.")
    raise  # never swallow interrupts or SystemExit

วิธีที่ 7 — จัดการกับความล้มเหลวหลายครั้งด้วย ExceptionGroup และยกเว้น* (Python 3.11+)

ขั้นตอนที่ 1:ยกอันExceptionGroupเมื่อรวบรวมข้อผิดพลาดจากงานแบบขนานหรือแบบเป็นชุด

def run_tests(tests):
    errors = []
    for t in tests:
        try:
            t.run()
        except Exception as e:
            e.add_note(f"Test {t.name} failed")
            errors.append(e)
    if errors:
        raise ExceptionGroup("Batch failures", errors)

ขั้นตอนที่ 2:ใช้except*เพื่อจัดการเฉพาะประเภทข้อยกเว้นที่ตรงกันภายในกลุ่ม

try:
    run_tests(tests)
except* (ValueError, TypeError):
    print("Some data errors occurred.")
except* OSError:
    print("Some OS errors occurred.")

รูปแบบการแก้ปัญหาอย่างรวดเร็ว

  • การแยกวิเคราะห์อินพุต: wrapint()หรือfloat()กับexcept ValueErrorและเตือนผู้ใช้อีกครั้ง
  • ไฟล์ I/O: catchFileNotFoundError,PermissionErrorหรือทั่วไปOSErrorและเปลี่ยนไปใช้เส้นทางสำรอง
  • การเรียกเครือข่าย/API: ตรวจจับการหมดเวลา/ข้อผิดพลาดในการเชื่อมต่อเฉพาะไลบรารี และใช้การลองใหม่แบบมีขอบเขตพร้อมแบ็คออฟ
  • บันทึกประเภทและข้อความข้อยกเว้นเสมอ เพื่อร่องรอยที่สมบูรณ์ ให้ใช้logging.exception()หรือtraceback.print_exc().

รูปแบบที่เน้นบางอย่างเช่นเฉพาะเจาะจงexceptข้อelse/finallyและยามระดับบนสุดจะทำให้โปรแกรม Python ของคุณมีความยืดหยุ่นมากขึ้นโดยไม่ต้องซ่อนจุดบกพร่องจริง ๆ

Related Posts