Menu
Coddy logo textTech

מה זה פולימורפיזם (Polymorphism)?

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

מאת Kevin Spektor, מייסד שותף ו-CTO

עודכן ב-24 בספטמבר 2026

ב-Python, len("hello") מחזירה 5, len([4, 8, 15]) מחזירה 3, ו-len({"a": 1}) מחזירה 1. זה שם פונקציה אחד שמשמש לשלושה טיפוסים, וכל טיפוס סופר בדרך שלו: מחרוזת סופרת תווים, רשימה סופרת פריטים, מילון סופר מפתחות. המילה מגיעה מיוונית: poly, הרבה, ו-morph, צורה. קריאה אחת, צורות רבות של התנהגות.

איך פולימורפיזם עובד

קוד קורא למתודה לפי שם, כמו shape.area(). כשהשורה הזו רצה, השפה מסתכלת על האובייקט בפועל ומוצאת את area במחלקה של האובייקט עצמו. החיפוש הזה נקרא dynamic dispatch, והוא מה שמאפשר לשורה אחת לעשות עבודה שונה לאובייקטים שונים:

Circle 3.14
Square 9
Circle 12.57

Python מוצאת את המתודה כשהיא מחפשת קודם במחלקה של האובייקט, ואז במחלקות האב שלה בסדר קבוע שנקרא method resolution order. אם ל-Square לא הייתה area() משלה, החיפוש היה מגיע ל-Shape.area() וזורק NotImplementedError, סימן לכך שכל תת מחלקה חייבת לספק אחת.

הלולאה אף פעם לא בודקת איזו צורה היא מחזיקה. כדי להוסיף משולש, כותבים מחלקת Triangle עם area() משלה, והלולאה עובדת בלי שינוי. בלי פולימורפיזם, הלולאה הייתה צריכה ענף if isinstance(...) לכל צורה, ולערוך אותו בכל פעם שמופיעה צורה חדשה.

סוגי פולימורפיזם

סוגנקרא גםאיך הוא נראהמתי הגרסה נבחרת
תת טיפוס (subtype)פולימורפיזם בזמן ריצה, דריסת מתודות (overriding)תת מחלקה מחליפה מתודה של האב שלהבזמן שהתוכנית רצה
אד הוק (ad hoc)העמסה (overloading)שם אחד, כמה גרסאות לטיפוסי פרמטרים שונים; גם העמסת אופרטוריםבזמן קומפילציה ב-Java וב-C++
פרמטריGenerics, templatesקטע קוד אחד שעובד לכל טיפוס: List<T> ב-Java, vector<T> ב-C++בזמן קומפילציה

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

ב-Python יש את שלושתם, כל אחד בדרכו. דריסה עובדת כמו בדוגמת הצורות. אופרטורים כמו + הם פולימורפיזם אד הוק. פונקציות כמו max() ו-sorted() הן פרמטריות ברוחן: הן מקבלות רשימה של מספרים, מחרוזות או תאריכים, כל עוד אפשר להשוות בין הפריטים, ורמזי טיפוס כמו list[int] או TypeVar יכולים לציין את זה במפורש.

פולימורפיזם בזמן קומפילציה מול בזמן ריצה ב-Java

ב-Java יש את שני הסוגים, ושאלות בראיונות עבודה שואלות לעתים קרובות על ההבדל:

class Animal { String sound() { return "..."; } }
class Dog extends Animal {
    @Override String sound() { return "Woof"; }
}

Animal pet = new Dog();
pet.sound();          // "Woof": chosen at run time from the object

int add(int a, int b)          { return a + b; }
double add(double a, double b) { return a + b; }
add(2, 3);            // int version, chosen by the compiler
add(2.5, 1.0);        // double version

המשתנה pet הוא מטיפוס Animal, ובכל זאת הגרסה של Dog רצה, כי הבחירה תלויה באובייקט ולא במשתנה. שתי מתודות ה-add הן העמסה: הקומפיילר בוחר אחת לפי טיפוסי הארגומנטים לפני שהתוכנית רצה. ממשקים נותנים את אותה התנהגות בזמן ריצה בלי לשתף קוד: כל מחלקה שמממשת Comparable אפשר למיין עם Collections.sort. C++ עובדת באותה דרך עם הבדל אחד: מתודה מקבלת dispatch בזמן ריצה רק אם הוכרזה כ-virtual. ראו פולימורפיזם ב-Java, העמסת מתודות ופונקציות וירטואליות ב-C++.

פולימורפיזם ב-Python: duck typing ואופרטורים

Python לא דורשת מחלקת אב משותפת. אם לאובייקט יש את המתודה שהקוד קורא לה, זה עובד: "אם זה הולך כמו ברווז ומגעגע כמו ברווז, זה ברווז". גם אופרטורים הם פולימורפיים. כתיבת a + b קוראת ל-a.__add__(b), כך שהמחלקות שלכם יכולות לתמוך ב-+, ב-len() וב-print():

3 abcd [1, 2]
Vector(11, 22)
5 3 2

הורשה היא דרך אחת להשיג פולימורפיזם, לא דרישה. Vector לא יורשת משום דבר מיוחד, ובכל זאת len() ו-+ מתייחסים אליה כמו לטיפוס מובנה. התיעוד על הורשה ב-Python מראה את הדרך של תת מחלקות.

טעויות נפוצות

לצפות ש-Python תעמיס לפי חתימה. def שני עם אותו שם מחליף בשקט את הראשון:

Hi Ana Silva
Traceback (most recent call last):
  ...
TypeError: greet() missing 1 required positional argument: 'last'

השתמשו בארגומנט עם ערך ברירת מחדל במקום: def greet(first, last="").

לשכוח virtual ב-C++. בלעדיו, קריאה למתודה דרך מצביע למחלקת הבסיס מריצה את הגרסה של הבסיס, גם כשהאובייקט הוא תת מחלקה.

דריסות שמשנות את המשמעות. אם area() בתת מחלקה אחת מחזירה את ההיקף, כל קורא שסומך על area() נשבר. דריסה חייבת לקיים את ההבטחה שהאב נתן; הכלל הזה ידוע כעקרון ההחלפה של ליסקוב (Liskov substitution principle).

בדיקות טיפוס בכל מקום. שרשרת של ענפי if type(x) == ... היא בדרך כלל סימן שכל טיפוס צריך לשאת מתודה משלו.

לאן ממשיכים מכאן

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

שאלות נפוצות

מה דוגמה לפולימורפיזם?
האופרטור + ב-Python: 1 + 2 מחבר מספרים, "ab" + "cd" משרשר מחרוזות ו-[1] + [2] משרשר רשימות. אותו סימן עובד על שלושה טיפוסים, וכל טיפוס מחליט מה הוא אומר. בקוד מונחה עצמים, הדוגמה הקלאסית היא רשימה של צורות שבה כל אחת עונה על area() עם הנוסחה שלה.
מה ההבדל בין פולימורפיזם להורשה?
הורשה מאפשרת למחלקה להשתמש מחדש בקוד של מחלקת אב. פולימורפיזם מאפשר לקוד לטפל בטיפוסים שונים דרך ממשק משותף אחד. הורשה היא דרך נפוצה אחת להשיג פולימורפיזם, כי תת מחלקה יכולה לדרוס מתודה של האב, אבל duck typing של Python וממשקים של Java נותנים פולימורפיזם בלי לשתף שום קוד.
מה זה פולימורפיזם בביולוגיה?
בביולוגיה, פולימורפיזם פירושו ששתי צורות או יותר של תכונה או של גן קיימות באותה אוכלוסייה, כמו סוגי הדם A, B, AB ו-O אצל בני אדם. יש לו אותו שורש יווני, "צורות רבות", כמו למונח מעולם התכנות, אבל שני המושגים לא קשורים זה לזה.
האם Python תומכת בהעמסת מתודות (method overloading)?
לא לפי טיפוסים או מספר של פרמטרים, כמו ש-Java ו-C++ עושות. def שני עם אותו שם מחליף את הראשון. קוד Python משיג את אותה תוצאה עם ארגומנטים עם ערך ברירת מחדל, עם *args, או עם functools.singledispatch, שבוחר פונקציה לפי הטיפוס של הארגומנט הראשון.
למה פולימורפיזם שימושי?
הוא מאפשר להוסיף טיפוסים חדשים בלי לשנות את הקוד שמשתמש בהם. תוכנת ציור שקוראת ל-shape.draw() על כל צורה לא צריכה שום עריכה כשמוסיפים מחלקת משולש; כותבים רק את המחלקה החדשה. בלי פולימורפיזם, הלולאה הזו הייתה מקבלת ענף if חדש לכל טיפוס.
איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל