Exceptions ו-Logging מערך שיעור למרצה

מערך שיעור: Exceptions ו-Logging

משך: יום לימוד מלא — 6 שעות אקדמיות (270 דקות).

מטרת השיעור: הסטודנטים יבינו שכשלים הם חלק טבעי מתוכנה, ויידעו לכתוב קוד שמזהה בעיות (raise), מטפל בהן (try/except) ומתעד אותן (logging), במקום לקרוס או להסתיר אותן.

בסוף השיעור הסטודנטים צריכים:

  1. לכתוב try/except/else/finally ולחזות במדויק אילו בלוקים ירוצו בכל תרחיש.
  2. לזרוק ValueError/TypeError עם הודעה ברורה כדי לבצע Validation בפונקציה, ולתפוס אותן אצל מי שקרא.
  3. להגדיר Logging לקובץ עם רמות מתאימות, ולרשום שגיאות עם Traceback בעזרת logging.exception.

דגש קריטי: “הפונקציה מזהה וזורקת, מי שקרא מחליט.” זה העיקרון שמחבר Exceptions ל-OOP (Validation במחלקות, נושא OOP) ול-FastAPI (שגיאה → תשובת HTTP, נושא Backend ומסדי נתונים).


מהלך השיעור

חלק בשיעורמשךהערות ודגשים
פתיחה: תוכנה שקורסת10 דק'המרצה מריץ מחשבון קטן ושולח לו “hello” — והוא קורס. “איך מונעים את זה?”
try / except40 דק'safe_age.py, ואז safe_divide.py. להדגים את הסכנה של except: ריק (Ctrl+C לא עובד!).
else / finally35 דק'“חזה את הפלט” על הלוח. דוגמת החיבור עם return. להדגיש: finally רץ גם אחרי return.
הפסקה15 דק'
raise40 דק'למה print/None גרועים. withdraw → atm_safe. Validation בהרשמה.
Logging א’: print מול logging, רמות35 דק'log_levels.py: לשנות רמה ולראות את הסינון. “בחר רמה” בכיתה.
הפסקה15 דק'
Logging ב’: קובץ, logging.exception35 דק'payments.py + tail -f / Get-Content -Wait בשני Terminals.
תרגול + בדוק את עצמך45 דק'Mini Project “מעבד הזמנות עמיד”.

דגשים להעברת השיעור

  • להתחיל מכאב אמיתי. שרת שקורס בגלל לקוח אחד הוא מוטיבציה טובה יותר מכל הגדרה.
  • “try קטן” — לחזור על זה כל הזמן. סטודנטים נוטים לעטוף פונקציה שלמה ב-try.
  • שאלת “האם לתפוס כאן?” — בדוגמה של divide שמחזירה 0: לעצור ולשאול את הכיתה אם זו תשובה נכונה. מכאן לעבור באופן טבעי ל-raise.
  • הודעות שגיאה הן UX למפתחים. לבקש מהסטודנטים לשפר הודעה גרועה (“error”) להודעה טובה (כלל + ערך שהתקבל).
  • Logging מול print: החלוקה היא “למשתמש” לעומת “למפתח”. להראות את שניהם באותה תוכנית (payments.py).
  • מוסכמת %s ב-logging: להסביר בקצרה למה (ביצועים), אבל לא להתעכב. f-strings לא נלמדו עדיין, ולכן לא להציג אותם כחלופה.
  • אבטחה: הדגש “לא לרשום סיסמאות” הוא הרגל מקצועי חשוב. כדאי להזכיר מקרים מפורסמים של דליפות מלוגים.
  • dict ו-tuple מופיעים היום בקצרה (catalog, for name, age in ...). להגיד במפורש שמחר נלמד אותם כמו שצריך.

מושגים

מושגהסבר קצר
Exceptionאובייקט שגיאה ש-Python זורקת בזמן ריצה.
Raise / Throwזריקת שגיאה.
Catchתפיסת שגיאה עם except.
try / except / else / finallyנסה / אם נכשל / אם הצליח / תמיד.
as errorגישה לאובייקט השגיאה ולהודעה שלו.
Validationבדיקת תקינות של קלט לפני השימוש בו.
Re-raiseraise לבד בתוך except, שמעביר את אותה שגיאה הלאה.
ValueError / TypeErrorערך לא חוקי / טיפוס לא נכון.
Log / Log Recordיומן אירועים / רשומה בודדת בו.
Log LevelDEBUG, INFO, WARNING, ERROR, CRITICAL.
basicConfigהגדרה חד-פעמית של רמה, פורמט ויעד.
filemode a / wהוספה לקובץ / דריסה.
logging.exceptionרשומת ERROR עם Traceback מלא.

תרגיל חשיבה

שאלת פתיחה (לפני raise): “כתבתי פונקציה שמחשבת הנחה: apply_discount(price, percent). מישהו קרא לה עם percent=150. מה הפונקציה צריכה לעשות?”

מהלך:

  1. לאסוף אפשרויות על הלוח: להחזיר 0, להחזיר את המחיר המקורי, להדפיס שגיאה, להחזיר None, להגביל ל-100, לזרוק שגיאה.
  2. לכל אפשרות לשאול: “מה יקרה למי שקרא, אם הוא לא שם לב?” (מחיר שלילי בעגלה, מוצר בחינם, None שגורם לקריסה 50 שורות אחר כך).
  3. לשאול: “מי יודע מה נכון לעשות: הפונקציה, או המסך/השרת שקרא לה?”
  4. להוביל ל: הפונקציה מזהה (150 לא חוקי), ומי שקרא מחליט (הודעה למשתמש, תשובת HTTP 400, לוג).

מה המרצה מראה בסוף: אותה apply_discount עם raise ValueError("percent must be 0-100, got 150"), ושני “קוראים” שונים: אחד מדפיס הודעה ידידותית, השני רושם ללוג ומחזיר שגיאה. משפט סיום: “שגיאה שנזרקת בקול עדיפה על באג שקט — את הראשונה רואים מיד, את השני מגלים אחרי חודש.”