מערך שיעור: Exceptions ו-Logging
משך: יום לימוד מלא — 6 שעות אקדמיות (270 דקות).
מטרת השיעור: הסטודנטים יבינו שכשלים הם חלק טבעי מתוכנה, ויידעו לכתוב קוד שמזהה בעיות (raise), מטפל בהן (try/except) ומתעד אותן (logging), במקום לקרוס או להסתיר אותן.
בסוף השיעור הסטודנטים צריכים:
- לכתוב try/except/else/finally ולחזות במדויק אילו בלוקים ירוצו בכל תרחיש.
- לזרוק
ValueError/TypeErrorעם הודעה ברורה כדי לבצע Validation בפונקציה, ולתפוס אותן אצל מי שקרא. - להגדיר Logging לקובץ עם רמות מתאימות, ולרשום שגיאות עם Traceback בעזרת
logging.exception.
דגש קריטי: “הפונקציה מזהה וזורקת, מי שקרא מחליט.” זה העיקרון שמחבר Exceptions ל-OOP (Validation במחלקות, נושא OOP) ול-FastAPI (שגיאה → תשובת HTTP, נושא Backend ומסדי נתונים).
מהלך השיעור
| חלק בשיעור | משך | הערות ודגשים |
|---|---|---|
| פתיחה: תוכנה שקורסת | 10 דק' | המרצה מריץ מחשבון קטן ושולח לו “hello” — והוא קורס. “איך מונעים את זה?” |
| try / except | 40 דק' | safe_age.py, ואז safe_divide.py. להדגים את הסכנה של except: ריק (Ctrl+C לא עובד!). |
| else / finally | 35 דק' | “חזה את הפלט” על הלוח. דוגמת החיבור עם return. להדגיש: finally רץ גם אחרי return. |
| הפסקה | 15 דק' | |
| raise | 40 דק' | למה print/None גרועים. withdraw → atm_safe. Validation בהרשמה. |
| Logging א’: print מול logging, רמות | 35 דק' | log_levels.py: לשנות רמה ולראות את הסינון. “בחר רמה” בכיתה. |
| הפסקה | 15 דק' | |
| Logging ב’: קובץ, logging.exception | 35 דק' | 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-raise | raise לבד בתוך except, שמעביר את אותה שגיאה הלאה. |
| ValueError / TypeError | ערך לא חוקי / טיפוס לא נכון. |
| Log / Log Record | יומן אירועים / רשומה בודדת בו. |
| Log Level | DEBUG, INFO, WARNING, ERROR, CRITICAL. |
| basicConfig | הגדרה חד-פעמית של רמה, פורמט ויעד. |
| filemode a / w | הוספה לקובץ / דריסה. |
| logging.exception | רשומת ERROR עם Traceback מלא. |
תרגיל חשיבה
שאלת פתיחה (לפני raise): “כתבתי פונקציה שמחשבת הנחה: apply_discount(price, percent). מישהו קרא לה עם percent=150. מה הפונקציה צריכה לעשות?”
מהלך:
- לאסוף אפשרויות על הלוח: להחזיר 0, להחזיר את המחיר המקורי, להדפיס שגיאה, להחזיר
None, להגביל ל-100, לזרוק שגיאה. - לכל אפשרות לשאול: “מה יקרה למי שקרא, אם הוא לא שם לב?” (מחיר שלילי בעגלה, מוצר בחינם,
Noneשגורם לקריסה 50 שורות אחר כך). - לשאול: “מי יודע מה נכון לעשות: הפונקציה, או המסך/השרת שקרא לה?”
- להוביל ל: הפונקציה מזהה (150 לא חוקי), ומי שקרא מחליט (הודעה למשתמש, תשובת HTTP 400, לוג).
מה המרצה מראה בסוף: אותה apply_discount עם raise ValueError("percent must be 0-100, got 150"), ושני “קוראים” שונים: אחד מדפיס הודעה ידידותית, השני רושם ללוג ומחזיר שגיאה. משפט סיום: “שגיאה שנזרקת בקול עדיפה על באג שקט — את הראשונה רואים מיד, את השני מגלים אחרי חודש.”