מערך שיעור: עבודה נכונה עם Objects ו-Encapsulation
משך: יום לימוד מלא — 6 שעות אקדמיות (270 דקות).
מטרת השיעור: להעמיק מ"איך כותבים Class" ל"איך כותבים Class טובה": שמירה על כללים, הסתרת מימוש, ועבודה נכונה עם הרבה אובייקטים שמחזיקים הפניות זה לזה.
בסוף השיעור הסטודנטים צריכים:
- להבחין בין Instance ל-Class Attributes, ולהימנע משתי המלכודות (השמה דרך אובייקט, רשימה משותפת).
- להסביר למה Encapsulation קיימת, ולממש אותה עם
_x, properties לקריאה בלבד, Setters עם ולידציה והחזרת עותקים. - לבנות Class שלמה לפי תהליך: אחריות → נתונים → ממשק → כללים → מימוש → בדיקה.
דגש קריטי: ה"למה" של Encapsulation. הסילבוס מדגיש זאת במפורש. לא ללמד את _ ו-@property כתחביר, אלא קודם להראות את account.balance = -1000000 עוקף את כל הבדיקות, ורק אז את הפתרון.
מהלך השיעור
| חלק בשיעור | משך | הערות ודגשים |
|---|---|---|
| חזרה: self ו-init | 10 דק' | 3 שאלות מהירות, כולל “takes 2 positional arguments but 3 were given”. |
| Attribute מול Method, Class Attributes | 35 דק' | אנלוגיית הלוח בכיתה. מונה ו-VAT. שתי המלכודות בהדגמה חיה. |
| הרבה אובייקטים ו-State | 35 דק' | Team, ואז Orders שמחזיקים Customer. לשנות עיר של דנה ולראות בשתי ההזמנות. ציור הפניות. |
| הפסקה | 15 דק' | |
| Encapsulation | 40 דק' | פתיחה: “תשברו לי את החשבון בשורה אחת”. אנלוגיית הכספומט. _ מול __, עם הדגמה של Name Mangling. |
| Getters / Setters / @property | 40 דק' | קודם get_/set_ (הרעיון), ואז @property (הפתרון של Python). RecursionError בכוונה. |
| הפסקה | 15 דק' | |
| בניית Class שלמה | 45 דק' | Course ביחד על הלוח: 4 שלבי התכנון לפני שורת קוד אחת. אחר כך המימוש והבדיקה. |
| תרגול + בדוק את עצמך | 35 דק' | Mini Project: בנק מוגן. לדרוש הערת תכנון בראש הקובץ. |
דגשים להעברת השיעור
- מלכודת ה-Class Attribute (רשימה משותפת) היא אחד הבאגים הקלאסיים של Python. להראות אותה, ואת הקשר לבאג של
def f(x=[])מנושא Python. אותו עיקרון בדיוק. - Encapsulation ב-Python היא מוסכמה. סטודנטים שמכירים Java ישאלו “אבל אפשר לעקוף!”. נכון, וזו הפילוסופיה: מבהירים כוונה, לא נועלים. להשוות לשלט “אין כניסה” לעומת דלת נעולה.
- לא להגזים ב-properties. להדגיש “מתחילים עם Attribute רגיל, משדרגים כשיש כלל”. זה גם יתרון אמיתי של Python על פני get/set בשפות אחרות.
- “להחזיר עותק” הוא חיבור יפה בין נושא Python (Mutable) ל-Encapsulation. לתת לסטודנטים לגלות את החור בעצמם.
- תהליך 6 השלבים: לעשות את שלבי התכנון בקול, עם הכיתה. סטודנטים צריכים לראות שמקצוענים חושבים לפני שהם מקלידים.
- Decorators: להציג
@propertyכתבנית, ולא להיכנס לאיך Decorators עובדים.
מושגים
| מושג | הסבר קצר |
|---|---|
| Instance Attribute | נתון של כל אובייקט בנפרד (self.x). |
| Class Attribute | נתון משותף ל-Class (בגוף ה-Class). |
| State | ערכי ה-Attributes ברגע מסוים. |
| Reference | אובייקט שמחזיק הפניה לאובייקט אחר, ולא עותק. |
| List Comprehension | דרך קצרה לבנות רשימה מסוננת. |
| Encapsulation | אריזת נתונים עם הקוד שלהם וחשיפת ממשק בלבד. |
| Public Interface / Implementation | מה שמיועד לשימוש מבחוץ / הפרטים הפנימיים. |
_x / __x | פנימי (מוסכמה) / Name Mangling. |
| Getter / Setter | מתודה לקריאה / מתודה לכתיבה עם ולידציה. |
@property / @x.setter | Getter/Setter בתחביר של Attribute. |
| Read-only Property | property בלי Setter. |
| Computed Property | property שמחושב מנתונים אחרים. |
| Validation | בדיקת תקינות לפני שמירה. |
| Invariant | תנאי שחייב להיות נכון תמיד. |
תרגיל חשיבה
שאלת פתיחה (לפני Encapsulation): “יש לנו את BankAccount מאתמול, עם withdraw שבודקת יתרה. אני אתן לכם 60 שניות: תשברו את החשבון — תגרמו ליתרה שלילית — בשורת קוד אחת.”
מהלך:
- רוב הכיתה תמצא תוך שניות:
account.balance = -1000000. - לשאול: “אז מה הטעם בכל הבדיקות שכתבנו ב-
withdraw?” - לשאול: “ואם בעוד חודש נחליט לשמור את היתרה באגורות (
balance_cents), כמה מקומות בקוד יישברו?” כל מקום שנגע ב-balanceישירות. - להציג את שתי מטרות ה-Encapsulation: הגנה על כללים והסתרת מימוש.
- להראות את הפתרון בשלבים:
_balance→get_balance()→@propertyלקריאה בלבד.
מה המרצה מראה בסוף: את אותו ניסיון “שבירה” על הגרסה החדשה: account.balance = -1000000 → AttributeError: property 'balance' ... has no setter. ואז את ההשוואה מול הכספומט: ממשק (מקשים) מול כספת (מימוש). משפט סיום: “Class טובה היא כמו כספומט טוב — קל להשתמש בה נכון, וקשה להשתמש בה לא נכון.”