Menu

חריגות ב-Python: try, except, else, finally ו-raise

איך מטפלים בשגיאות ב-Python: try/except/finally, תפיסת חריגות ספציפיות, זריקת חריגות משלכם, ומתי לתת לשגיאה להמשיך הלאה.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

שגיאות הן פשוט ערכים עם גישה רעה

כשמשהו משתבש ב-Python (חילוק באפס, קריאה של קובץ חסר, פענוח של מספר לא תקין), סביבת הריצה יוצרת אובייקט חריגה (exception) ומתחילה לפרק את מחסנית הקריאות עד שמשהו תופס אותה. אם שום דבר לא תופס, התוכנית מסתיימת ומדפיסה traceback.

חריגות הן לא דבר רע כשלעצמן. הן הדרך של Python לאותת "אני לא יכולה להמשיך בפעולה הזו; הנה למה". התפקיד שלכם הוא להחליט, מקרה אחרי מקרה, מאילו מהן אתם יודעים להתאושש ואילו כדאי לתת להן לעלות למעלה.

הצורה הבסיסית

  • try: פותח את בלוק הקוד המסוכן.
  • except ValueError: תופס את החריגה הספציפית הזו אם היא נזרקת בתוך ה-try.
  • אם לא נזרקת חריגה, מדלגים על ה-except לגמרי.

הריצו את הקטע עם 42: זה עובד. הריצו אותו עם hello: המטפל רץ.

תפיסת חריגות ספציפיות

ל-Python יש היררכיה של סוגי חריגות. כמה מהן תפגשו הרבה:

  • ValueError: ערך היה שגוי בדרך כלשהי (int("abc"), ארגומנטים מחוץ לטווח).
  • TypeError: נעשה שימוש ב_טיפוס_ הלא נכון ("hi" + 3).
  • KeyError: מפתח לא נמצא ב-dict.
  • IndexError: אינדקס ברצף היה מחוץ לטווח.
  • FileNotFoundError: קובץ לא קיים.
  • ZeroDivisionError: ניסיון לחלק באפס.
  • AttributeError: לאובייקט אין את התכונה המבוקשת.

תפסו את החריגה הספציפית שאתם יודעים לטפל בה:

אפשר לתפוס כמה חריגות בפסקה אחת על ידי העברת tuple:

שימו לב ל-as e. הוא קושר את אובייקט החריגה ל-e, כדי שתוכלו לבדוק את ההודעה או התכונות שלו.

הימנעו מתפיסה של הכל

except: חשוף תופס ממש כל דבר, כולל KeyboardInterrupt (ה-Ctrl-C שלכם) ויציאות ברמת המערכת. אל תשתמשו בו.

except Exception: קצת יותר טוב, אבל עדיין מסוכן: הוא בולע באגים שלא צפיתם ומסתיר את המקור האמיתי של הבעיות:

# אל תעשו את זה בלי סיבה ממש טובה.
try:
    do_something()
except Exception:
    pass

הצעד הנכון הוא כמעט תמיד לתפוס את החריגה הספציפית שאתם יודעים להתאושש ממנה. אם חריגה שלא ציפיתם לה מגיעה לראש התוכנית, ה-traceback אומר לכם בדיוק מה השתבש: זה פיצ'ר, לא באג.

else ו-finally

להצהרת try יש עוד שתי פסקאות אופציונליות:

  • else רץ אם בלוק ה-try הסתיים בלי לזרוק חריגה.
  • finally רץ לא משנה מה: עם חריגה או בלי.

else הוא המקום הנקי ביותר לקוד של "רק במקרה של הצלחה": לא רוצים שבלוק try יעשה יותר מהחלק שבאמת יכול להיכשל. finally מיועד לניקוי שחייב לרוץ גם אם ה-try נכשל: סגירת משאב, שחרור lock, שחזור מצב.

זריקת חריגות בעצמכם

השתמשו ב-raise כדי לאותת על שגיאה בקוד שלכם:

בחרו סוג חריגה שמתאים למה שהשתבש. פנו קודם לחריגות המובנות, ValueError, TypeError, FileNotFoundError, לפני שאתם מגדירים מחלקה משלכם.

הגדרת חריגה משלכם

כשהחריגות המובנות לא מבטאות את המשמעות, הגדירו חריגה מותאמת אישית:

רשו מ-Exception (או מחריגה מובנית ספציפית יותר) ותנו למחלקה docstring. בדרך כלל זה כל מה שצריך. חריגות מותאמות אישית מאפשרות לקוד הקורא לתפוס רק את השגיאה שמשמעותית לתחום שלו.

raise ... from ...: חריגות משורשרות

כשחריגה אחת גורמת לאחרת, שמרו על השרשרת:

ה-from e מצרף את השגיאה המקורית. כשה-traceback מודפס, Python מציגה את שתיהן: את ה-ConfigError שעלתה למעלה ואת ה-FileNotFoundError שגרמה לה. שובל כזה שווה זהב בזמן דיבוג.

Context Managers: הדרך הנקייה יותר לנקות

finally זה בסדר, אבל למשאבים כמו קבצים, context manager (מה ש-with משתמש בו) עדיף כמעט תמיד:

# גרסה עם finally
f = open("data.txt")
try:
    data = f.read()
finally:
    f.close()

# גרסה עם with
with open("data.txt") as f:
    data = f.read()

שתי הגרסאות בטוחות. הצורה עם with קצרה יותר ופועלת אוטומטית. פנו ל-finally רק כשאתם עושים משהו שהספרייה הסטנדרטית עוד לא עוטפת ב-context manager.

מתי לא לתפוס

תפיסת חריגה היא החלטה: אתם אומרים "אני יכול לטפל בזה". אם אתם לא יכולים, תנו לחריגה להמשיך הלאה. קוד כזה הוא כמעט תמיד טעות:

try:
    do_work()
except Exception:
    pass  # מתעלמים מהכל בשקט

השתקת שגיאות הופכת באגים לבלתי נראים. עדיף לקרוס ברעש מאשר לדדות הלאה במצב לא עקבי.

לסיכום

  • try/except מאפשרים לטפל בשגיאות שאפשר להתאושש מהן.
  • תפסו חריגות ספציפיות, לא Exception באופן גורף.
  • raise מאותת על שגיאות בקוד שלכם.
  • בלוקים של with מחליפים את רוב הניקוי עם finally.
  • כשיש ספק, תנו לחריגה להמשיך הלאה.

בהמשך: סיור בשגיאות הספציפיות ש-Python זורקת הכי הרבה, KeyError, ValueError, ModuleNotFoundError ועוד כמה, יחד עם הרגלי הדיבוג שמתקנים אותן מהר.

שאלות נפוצות

איך מטפלים בשגיאות ב-Python?

עטפו קוד מסוכן בבלוק try ותפסו את החריגה הספציפית בבלוק except: try: risky() except ValueError: .... בלוק else אופציונלי רץ אם לא קרתה חריגה; finally רץ בכל מקרה, לצורך ניקוי.

כדאי לתפוס Exception ליתר ביטחון?

לא. except: חשוף או except Exception: מסתירים באגים שלא צפיתם. תפסו את החריגה הספציפית שאתם יודעים להתאושש ממנה, ותנו לכל השאר להמשיך הלאה כדי שתראו את הבעיה האמיתית.

מה ההבדל בין raise ל-raise from?

raise NewError(...) זורקת חריגה חדשה. raise NewError(...) from original שומרת את החריגה המקורית מחוברת בתור הסיבה, ו-Python מציגה אותה ב-traceback. השתמשו ב-from כששגיאה ברמה נמוכה גרמה לשגיאה ברמה גבוהה יותר שאתם רוצים להציף.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל