3 min. read

פרק קודם:

פייתון 15 - רגקסים

מה נלמד

  • מהי מחלקה ומהו מופע
  • תכנות מונחה X
  • תכנות מונחה עצמים - Object Oriented Programming (OOP)
  • מהם אובייקטים וכיצד להגדיר אותם
  • עיצוב ותכנון נכון של אובייקטים
  • עקרונות תכנות מונחה עצמים
שימו ❤ : הפרק הזה יהיה תיאורטי והפרק הבא יהיה יותר מעשי.

לאורך הפרקים הקודמים לא הזכרתי אובייקטים במובן שלהם - קראתי להם “משתנה מסוג מסוים”.
וזו הגדרה לא שקרית - אובייקטים הם משתנים מסוג מסוים - סוג שאנחנו יכולים להגדיר.

אנלוגיה לתרשימים ובנייה

בתכנות יש שימוש רב באנלוגיות ומטאפורות - משהו ווירטואלי שמדמה משהו פיזי.

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

ואז נוכל לקחת את התרשים ולבנות ממנו בית פיזי,
הבית הזה יכול להיבנות יותר מפעם אחת:

כעת נכיר שני מושגים חדשים:

  • Class - מחלקה/אובייקט
  • Instance - מופע/עצם

כל תרשים הוא מחלקה וכל בנייה של בית זהו מופע חדש.

מהו “תכנות מונחה משהו”

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

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

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

  • פרטי אשראי
  • רשימת מוצרים לקנייה

הדברים שאנחנו צריכים לעשות:

  • לסכום את המוצרים
  • להוציא בקשת הרשאה בעזרת הכרטיס אשראי לחברת האשראי
  • להחזיר אם זה הצליח או לא.

אז לפי הדברים שאנחנו צריכים לעשות אנחנו יכולים להגדיר פונקציות רלוונטיות:

1
2
3
4
5
6
7
8
9
10
11
def __SumProductsCost(products)
return sum(product.cost for product in products)

def __PayForProducts(creditCard, totalCost):
successResult = InitiateTransaction(creditCard)
successResult = Pay(creditCard, totalCost)
return successResult

def PayForProducts(creditCard, products):
cost = __SumProductsCost(products)
return __PayForProducts(creditCard, cost)

כאן הגדרנו 3 פונקציות כאשר 2 מהם הם “פרטיות” - ז”א מי שמשתמש בפונקציות האלו לא צריך לגעת בהן,
אלה רק להשתמש ב-PayForProducts.

הגדרנו 3 בלוקים בסיסיים שמקבלים נתונים ומוציאים סטטוס אם זה הצליח או לא.

תכנות מונחה עצמים - Object Oriented Programming

עצם/אובייקט/מחלקה זהו אוסף של משתנים ופונקציות.
או במילים אחרות יש לאובייקט מידע ופעולות.

בפייתון קיימים אובייקטים רבים והשתמשמתם בהם כבר לאורך המדריכים:

  • רשימות
  • מילונים
  • אובייקט match של רגקס
  • אובייקט קובץ
    בעצם בפייתון יש הרבה מאוד אובייקטים, כמעט הכל זה אובייקטים!

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

עיצוב בעזרת אובייקטים

זהו החלק המורכב יותר שצריך לעשות בהתחלה - לחשוב בעזרת אובייקטים.
התהליך הזה נקרא בעצם עיצוב - אנחנו מעצבים איך הקוד שלנו ייראה .
חשיבה מוקדמת עוזרת למקד את הקוד בלפתור את הבעיה.
כלל אצבע:

הרבה יותר קל למחוק מנייר מאשר לשנות הרבה שורות קוד

נחשוב על איזה אובייקטים יש לנו במערכת להזמנת מוצרים דרך האינטרנט:

  • כרטיס אשראי

  • מספר כרטיס

  • תאריך תפוגה

  • 3 ספרות של הכרטיס

  • תעודת זהות של בעל הכרטיס

  • מוצר

  • שם מוצר

  • מחיר

  • כמות

עכשיו נשאל את עצמנו “מה האובייקטים האלו יכולים לעשות?”

כרטיס אשראי ניתן לשלם דרכו,
לבטל הזמנה,
לבטל כרטיס.

מה מוצר יודע לעשות?
לא משהו שייעזור לנו כרגע - מוצר הוא אובייקט עם מידע בלבד.
אובייקטים כאלו בדרך כלל נקראים “מודלים” - models.
או “Information object” - אובייקט מידע.

כעת נגדיר בפסודו-קוד איך האובייקטים האלו נראים ומתנהגים:

1
2
3
4
5
6
7
8
9
10
11
12
13
class CreditCard: 
- Number
- ExpirationDate
- BackNumber
- OwnerId
Pay(amount) # פונקציה
Cancel(orderId) # פונקציה
CancelCard() # פונקציה

class Product:
- Name
- Price
- Amount

כעת אם נרצה להגדיר כיצד אנחנו יכולים לעשות את מה שעשינו מקודם רק עם אובייקטים.
הקוד ייראה כמו משהו כזה:

1
2
3
4
5
6
7
8
9
10
11
12
creditCard = CreditCard() # יוצרים עצם חדש של המחלקה

ListOfProducts = ... # אנחנו משיגים את הרשימה של המוצרים

# נחשב כמה הכל עולה
sum = 0
for product in ListOfProducts
sum = sum + (product.Price * product.Amount)

# נשלם בעזרת כרטיס האשראי
creditCard.Pay(sum)

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

עקרונות תכנות מונחה עצמים

  • כימוס - Encapsulation
  • אבסטרקציה - Abstraction
  • ירושה - Inheritance
  • פולימורפיזם - Polymorphism

כימוס/מידור - Encapsulation

תכירו, זהו בוב:

בוב הוא בחור מוכשר, נהנה לתכנת ולדוג.

זוהי אליסה:

היא אסטרונומית ונהנת ללמד ילדים.

אנחנו יכולים לגלות עליהם דברים רק מלצפות בהם:

  • לבוב אין שיער
  • בוב לבוש בחולצה כחולה
  • לאליסה שיער כתום
  • לאליסה חולצה סגולה

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

בוב: מה הגיל שלך אליסה?
אליסה: אני בת 28, בן כמה אתה?
בוב: אני בן 29
במה את עובדת?
אליסה: אני אסטרונומית.

יש גם מידע פרטי שהאנשים לא יירצו לחלוק איתם:

בוב: איפה את גרה?
אליסה: אני לא מכירה אותך מספיק בשביל לומר לך את זה.

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

מידע של אובייקט הוא המצב שלו - ה-State, ואת המצב הפנימי של האובייקט יש לשמר בתוך האובייקט.
כמו המחשבות שלכם, כדי לדעת על מה אתם חושבים צריך לשאול אתכם, ממבט חיצוני לא נדע תמיד מה אתם חושבים.

הפשטה - Abstraction

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

למשל “מוצר חשמלי”.
אם נדמיין מוצר חשמלי אנחנו נדמיין מאורר, מיקרוגל, מקרר או כל דבר אחר שהוא חשמלי.
אבל אין למוצר חשמלי צורה בפני עצמה לכן עצם מסוג “מוצר חשמלי” הוא לא הגיוני.

תרגיל

להלן רשימות, על כל רשימה תבחרו את האבסטרקציה הרלוונטית.

  • ורד, עגבניה, היביסקוס וורבנה.
  • מלוח, מתוק, מר וחריף
  • תרנגול, קרוקודיל, כלב וחתול

ביט תכנותי:

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

ירושה - Inheritance

ירושה זה לקבל את הכל ממחלקה אחרת, כמו לקבל את הכסף מסבא!

אדם הוא מחלקה שמגדירה שם וגיל כי לכל אדם יש שם וגיל,
עובד הוא מחלקה שמגדירה גם משרה ושכר, אבל עובד הוא גם אדם!
אם עובד “יירש” מ-אדם הוא ייקבל את הערכים - גיל ושם.

טרמינולוגיה

ירושה זה בין מחלקת בן למחלקת אב.
או מחלקה בסיסית ומחלקה נגזרת כי המחלקה השנייה “גוזרת” ממחלקת הבסיס. (כמו בנגזרות).
הטרמינולוגיה הנפוצה היא מחלקת בסיס ומחלקה נגזרת או “מחלקה יורשת”.

הגדרת מחלקות בסיס

כדי לחשוב על מחלקת בסיס צריך לחשוב מה יכול להיות משותף לכולם.
למשל ניקח חיה, מה יהיה משותף לכל החיות?

  • מימדים
  • נוצות
  • גיל
  • שם
  • מספר רגליים
  • משקל

אז מה משותף ומה לא?

  • מימדים - כן משותף לכולם כי לכל חיה יש ייצוג פיזי.
  • נוצות - לא כי לא לכל החיות יש נוצות.
  • גיל - כן כי כל חיה נמצאת במרחב וזמן.
  • שם - לרוב החיות יש שם, אלה אם כן לא גילו אותן עדיין!
  • מספר רגליים - לא כי לא לכל החיות יש רגליים
    תאורטית ניתן להחזיר 0 אך בגלל שזה לא מייצג את כל החיות אנחנו לא נכניס את זה.
  • משקל - כן כי כל חיה עובדת לפי חוקי הפיזיקה.

אז זה מביא אותנו למחלקת בסיס כזו:

1
2
3
4
5
חיה:  
- מימדים
- גיל
- שם
- משקל

מה עם שאר הפרמטרים?
אנחנו יכולים ליצור מה שנקרא היררכיה של מחלקות.
זאת מכיוון שיש לנו כל מיני סוגים של חיות - עופות, זוחלים, יונקים וכדו’…
אז למשל ניקח את המאפיין של הנוצות, נוכל ליצור מחלקה נוספת שמייצגת חיות מעופפות וההיררכיה תראה כך:

1
2
3
4
5
6
7
8
9
10
11
חיה:  
- מימדים
- גיל
- שם
- משקל

חיה מעופפת יורשת מחיה:
- נוצות
- כנפיים
לעוף()

תחשבו עם הלוגיקה שלכם - מהי הבעתיות במידע על נוצות?

לא כל חיה מעופפת בעלי נוצות!
לכן זה לא יהיה נכון להכניס תחת הקטגוריה הזו את הנוצות.

ביט תכנותי:

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

ולבסוף נוכל לממש ברווז!

1
2
3
4
5
ברווז יורש מחיה מעופפת:  
- נוצות
- קוואק()
- לשחות()

וזה ייראה בסוף כך:

הברווז יורש את החיה המעופפת וכל חיה מעופפת זו חיה.
אז בסוף לברווז יהיה את כל התכונות של ההיררכיה:

1
2
3
4
5
6
7
8
9
ברווז:  
- קוואק()
- לשחות()
- נוצות
- מימדים
- גיל
- שם
- משקל

פולימורפיזם - Polymorphism

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

לבוב יש חיית מחמד בשם כיפלי.

כיפלי זו חיה לא ידועה לנו - זה כלב, זה חתול, נראה כמו ארנב בכלל?

אז כאן העקרון הפולימופורמי עובד, כיפלי הוא חיה ואנחנו לא יודעים איזה סוג של חיה זו, אז נוכל להגדיר בפסודו קוד:

1
Animal Kifli;

החיה הזו יכולה להיות כלב, ארנב, חתול או חיות דומות אחרות:

1
2
3
4
5
Animal kifli = Cat
# או
Animal kifli = Dog
# או
Animal kifli = Rabbit

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

1
2
3
4
5
6
Animal kifli = Dog

def PrintAnimal(animal):
print(animal.Name)

PrintAnimal(kifli)

לאליסה יש תוכי, כעת אם נרצה להשתמש בפונקציה כדי להדפיס את הפרטים על התוכי שלה, נוכל לעשות את זה!

1
2
3
4
5
6
Animal parrot = Parrot

def PrintAnimal(animal):
print(animal.Name)

PrintAnimal(parrot)

פולימורפיזם נותן לנו את היכולת לתת צורה שונה למשתנה בהתאם להיררכיית ההורשה.

ירושת יהלום - ירושה מרובה

לא כל שפות התכנות מאפשרות את זה אבל פייתון כן.
תוכי הוא גם יורש את חיה מעופפת וגם את חיה מדברת.
גם חיה מדברת וגם חיה מעופפת יורשת את חיה.
מה זה אומר לגבי המידע וההתנהגות של חיה? האם זה קיים פעמייים?

בפייתון קיימים מנגנונים שמגנים עלינו משגיאות ומה שייקרה זה שזה ייצור אותם לפי סדר מוגדר,
נלמד יותר לעומק על הסדר הזה בפרקים הבאים!


תרגיל

  1. מהי מחלקה?
    מהו עצם?
    מהו ההבדל בין מחלקה לעצם?

  2. תחברו בין המשפטים הנכונים:

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

תעצבו את המחלקות לתכנית שמנהלת ספרים.
הספרים מתקבלים במשלוח ויש לשים אותם במדפים המתאימים ע”פ הז’אנרים.

תשתמו בעקרונות שלמדנו, כמה נקודות שייעזרו לכם:

  • למחלקה יכולה להיות מידע והתנהגות (פונקציות)
  • מחלקות יכולות להיות בנויות ממחלקות אחרות
  • פרמטרים לפונקציות יכולות להיות מחלקות אחרות



בפרק הבא נעסוק בעצמים בפייתון, נלמד מה התחביר ואיך כותבים קוד מונחה עצמים איכותי.

פייתון 17 - מחלקות חלק ב

אהבתם? מוזמנים להביע תמיכה כאן: כוס קפה