פייתון/פייתון גרסה 3/מחלקה

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי

הקדמה[עריכה]

שפת תכנות מונחה עצמים[עריכה]

שפת פיתון היא שפת תכנות מונחה עצמים (אובייקטים), ובאנגלית: Object-Oriented Programming (או בקיצור OOP).[1]

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

צורך במחלקה[עריכה]

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

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

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

מחלקה[עריכה]

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

  • מספר קטלוגי, מטיפוס int
  • שם, מטיפוס מחרוזת.
  • מחיר, מטיפוס נקודה צפה
  • כמות (כמה יש במלאי), מטיפוס int לא-שלילי.

המחלקה מכילה בתוכה

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

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

מבנה[עריכה]

class Name:
    ''' documentation '''
    pass
  • נהוג לרשום את האות הראשונה של שם המחלקה באותיות גדולות.
  • נהוג לייצר מחלקה בקובץ חדש כאשר שם הדף החדש הוא שם המחלקה.

נתחיל את המחלקה פרטים:

class Point
    ''' documentation '''
	pass

הגדרת המחלקה הנ"ל מודיעה שיש כעת טיפוס חדש, ששמו Point.

גוף המחלקה ריק (זו משמעות המילה השמורה pass).

__init__[עריכה]

מתודת האתחול (initializer method) או פונקציה בונה (constructor) היא פונקציה הנמצאת בכל מחלקה.

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

בכדי ליצור את מתודת האתחול :

class Point:
    '''creats points with vaule x,y'''

    def__init__(self, name_metoda):
        ''' documentation '''
        self.filed_name = num\string\etc

נדגים הרצה :

class Point:
    '''creats points with vaule x,y'''

    def __init__(self):
        ''' documentation '''
        print('init:')

point = Point() #creates object

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

שדה[עריכה]

שדה מה הוא?[עריכה]

שדה הוא אוסף תכונות משותפות של אובייקטים. שדה נפתח במילה self.

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

בתוך השדה קיימים אוביקטים שונים, איקסים שונים שכולם מקיימים את אותה תכונה.

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

לעיתים מבלבלים בין שדה למופע במחלקה (ראה בהמשך).

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

self[עריכה]

בכדי ליצור שדה ב-init מקובל להשתמש במילה המקובלת "self". המילה "self" (תפקידה דומה למילה this בשאר השפות אך היא אינה מילה שמורה, ניתן להשתמש בשם אחר לפרמטר אך הוא נמצא בשימוש בקונבנציה).

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

אם לא יוגדר הפרמטר הראשון כלל, פייתון יקפיץ שגיאת TypeError, כי המהדר ינסה להכניס ארגומנט נוסף למתודה שאינו מוגדר.

דוגמה:

class Point:
    ''' have x and y positions '''

	def __init__(self,x,y):
		self.x=x
		self.y=y

יצירת עצמים (אובייקטים) למחלקה[עריכה]

אז איך יוצרים אובייקט?[עריכה]

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

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

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

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

יצירת אובייקט[עריכה]

האויבקט נוצר על ידי השמה של שם משתנה חדש (Member Variables) והשוואתו לשם מחלקה (ראו בדוגמה את הסעיף עם הערה creating new object!).

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

הקוד הבא, לדוגמה, מייצר אוביקט חדש מסוג המחלקה:

המחלקה שלנו, בפונקצית האתחול, מקבלת שני פרמטרים (x,y), ולכן בעת קריאה למחלקה עלינו להביא למחלקה פרמטרים אלו:

class Point:
	def __init__(self,x,y):
        "creats the filds x,y"
		self.x=x
		self.y=y

# Main:
point=Point(3,4) #creating new object!

print(point)
>>><__main__.Point object at 0x03035630>
print (point.x,point.y) 
>>>3 4

נתבונן על ה-main, ממנו מתחיל הקובץ לרוץ, ומפעיל את המחלקה.

[הנחנו אותו תחת הכותרת main מפני שיש לו קשר לפונקצית main עליו לא נרחיב בחלק זה אך חשוב להכיר שכן נהוג להוסיפה ברב התכניות 
הכוללות מחלקות.]

על כל פנים נבחין בהדפסות:

  1. כאשר קראנו למחלקה print(point) קבלנו את מיקום הפונקציה בדומה לקריאה לפונקצית המתכנת.
  2. כאשר הכנסנו את שני הפרמטרים שמקבלת פונקצית האתחול המחלקה רצה. בדומה לפונקצית המתכנת ניתן להגדיר פרמטר של ברירת מחדל.

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

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

אוביקט שניתן לשנותו[עריכה]

האוביקט הוא מופע (instance), פריט של המחלקה, טיפוס שניתן לשנותו (mutable) ולכן ניתן לגשת אליו.

class Point:
	def __init__(self,x,y):
		self.x=x
		self.y=y

# Main:
point=Point(3,4)

print (point.x,point.y)

point.x = 6
point.y = 7
print(point.x,point.y)
>>>6 7

מופע מחלקה[עריכה]

מופע מחלקה (attributes) הם משתנה גלובלי, פריטים בשדה של המחלקה.

נתבונן בדוגמה הקודמת:

point.x = 6
point.y = 7

במקרה זה קראנו לשני מאפייני מחלקה שהם למעשה מידע מתוך המופע (data item from an instance).

המשתנה ( instance,) קורא למחלקה בעלת שני מאפיינים, x ו-y, שמקשר למספר.

נשים לב כי המשתנה רק מחזיק בהפניה אל האוביקט כלומר הוא מייצר מצביע (alias). המצביע הוא מי ש"בונה את שלד" (constructor) של המחלקה.

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

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

משתנה מחלקה[עריכה]

מחלקה לא חייבת להכיל רק שדה אלא גם משתני מחלקה (class variables.

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

לדוגמה עבור מחלקת מכונית יהיה זה משתנה "גלגלים = 4"

מתודה[עריכה]

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

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

class Point:
    """  """

    def __init__(self, x, y):
        """  """
        self.x = x
        self.y = y

    def sum_x_y(self):
        """ the function return the sum of x+y """
        return (self.x + self.y)
#       return(sum_x_y, x)

# Main:
point=Point(3,4)

print(point.sum_x_y())
>>>7

המתודה יכולה להחזיר לנו מופע באמצעות בקשה לקבלת ערך החזרה בסוף (ראה הערה בדוגמה לעיל) כך שנגדיר משתנה :

class Point:
    """  """

    def __init__(self, x, y):
        """  """
        self.x = x
        self.y = y

    def sum_x_y(self):
        """ the function return the sum of x+y """
        return (self.x + self.y)



# Main:
point=Point(3,4)

point_2 = (Point.sum_x_y(point), point.x)

print(point_2)

=הרחבה על פונקצית self[עריכה]

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

class Point:
    nam_for_y = None

    def __init__(self, x):
        self.x = x
        self.y = Point.nam_for_y
        Point.nam_for_x = None

        if self.x :
            print(self) #print object

point = Point(3)
print(point) #print object

>>>
<__main__.Point object at 0x033F6770>
<__main__.Point object at 0x033F6770>

בשתי ההדפסות בין אם אנו קוראים ל-self או לאוביקט עצמו, פיתון מדפיסה לנו את אותו האוביקט

פונקצית str[עריכה]

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

class Point:
    """  """

    def __init__(self, x, y):
        """  """
        self.x = x
        self.y = y

    def sum_x_y(self):
        """ the function return the sum of x+y """
        return (self.x + self.y)

    def __str__(self):
        return (self.x, self.y)


# Main:
point=Point(3,4)

print(point.__str__())
>>>(3, 4)

נשם לב אם נקרא לפונקצית str או print ונבצע על point יוחזר לנו מיקום הפונקציה ולא הדפס:

class Point:
    """  """

    def __init__(self, x, y):
        """  """
        self.x = x
        self.y = y

    def sum_x_y(self):
        """ the function return the sum of x+y """
        return (self.x + self.y)



# Main:
point=Point(3,4)

print(point)
print(str(point))
>>><__main__.Point object at 0x037756F0>
>>><__main__.Point object at 0x037756F0>

ראה גם[עריכה]

  1. ^ עד על תכנות מונחה, מדריך C# - תכנות מונחה עצמים: מבוא