השנה 2023. הגיע הזמן להפסיק לדבר על ירושה בפייתון
הקונספט של ירושה בין מחלקות היה פופולרי כשכולם כתבו Java ו C++ בגלל שזו היתה הדרך היחידה לכתוב קוד פולימורפי. אם רצינו ב Java ליצור מערך של מוצרים ממחלקות שונות, היה עלינו לוודא שלכל המחלקות יש Base Class משותף, והשפה עצמה וידאה שאנחנו מתיחסים רק למאפיינים מה Base Class של הדברים מהמערך.
אני מבין את ההגיון הזה ב Java. אבל בפייתון? הנה הקוד למחלקה של עגלת קניות שמכילה 3 סוגים של מוצרים:
from dataclasses import dataclass
class Cart:
def __init__(self):
self.products = []
@dataclass
class Table:
price: float
name: str
@dataclass
class Shoes:
price: float
color: str
c = Cart()
c.products.append(Table(price=120, name="Big Table"))
c.products.append(Table(price=80, name="Small Table"))
c.products.append(Shoes(price=180, color="orange"))
יותר מזה, אני יכול להוסיף פונקציה ל Cart שתדפיס את המחיר הכולל של המוצרים:
class Cart:
def __init__(self):
self.products = []
def price(self):
return sum(p.price for p in self.products)
ואפשר להגדיר פרוטוקול כדי לבדוק טיפוסים בזמן כתיבת הקוד:
class Product(Protocol):
price: float
class Cart:
def __init__(self) -> None:
self.products: list[Product] = []
def price(self):
return sum(p.price for p in self.products)
ואז אפשר לקבל שגיאות כשמנסים להוסיף משהו שאין לו מחיר לעגלת הקניות, בדיוק כמו שהיה קורה ב Java.
תרחיש שני שאולי היה גורם למישהו לחשוב על יצירת עצי ירושה הוא שימוש חוזר בקוד. במקרה שלנו אפשר לדמיין קוד שיהיה משותף לכל המוצרים ולכן כדאי לכתוב אותו רק במחלקת הבסיס "ולרשת" את המימוש במחלקות של שאר המוצרים. לצערי גם כאן כל דוגמה שאני מצליח לחשוב עליה אני יכול לשכתב לקוד טוב יותר תוך שימוש במנגנונים אחרים לשימוש חוזר בקוד של השפה, בדגש על Descriptors ו Class Decorators. החיסרון בירושה הוא שאתה מקבל המון דברים במכה אחת ובלי לבקש אותם, ובלי אפשרות לשלוט באיזה פונקציונאליות בדיוק תקבל.
השנה 2023 וכבר מזמן אין סיבה להשתמש בירושה ב Python.