מה ההבדל בין __init__ ל-__new__?

מה שכתוב בכותרת ועוד 20 תווים

3 לייקים

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

.* יש מצב שיש הבדל גם בשימוש ב self בין השניים - כיוון ש new הוא יצירת המופע , ועבור init המופע כבר נוצר לפני

4 לייקים

5 לייקים

אז בעצם __init__ משתמשת ב-__new__ כדי ליצור את self?

אם כך, איזה שימושים פרקטיים יכולים להיות להגדרה מחדש של __new__?

י. init זו פעולה שמתבצעת אחרי שהמופע כבר נוצר, היא פשוט נקראת אוטומטית אחרי יצירת המופע, כמו לכתוב:
Class()
self.init()
לא חייבים init במחלקה לצורך העיניין - לא רוצה להכנס כאן לעיניינים של מקובלות וכו’ (כי זה לא) - אבל מבחינת ביצוע נטו, לא חייבים להגדיר init : אם הייתי רוצה, הייתי יכולה להגדיר מחלקה בלי תכונות בכלל ויותר מאוחר לקרוא לפעולה בשם שמתחשק לי להוסיף תכונות (נדמה לי שככה זה בדוגמאות הראשונות במחברת, לא?).
init לא ‘משתמשת’ ב new , כי init מתחילה אחרי ש new כבר נגמרה.
לעומת זאת, אתה לא יכול ליצור מופע בלי new. פייתון יוצרת את המופע עם new . אתה תשנה את new אם אתה רוצה ליצור מופע בצורה אחרת ממה שפייתון עושה, וזה החלק שאני לא יודעת: מתי רוצים לעשות את זה.

6 לייקים

עכשיו אני מבין, תודה!

לייק 1

אנסה לתת פה את ה־2 סנט שלי, עם דוגמה שאולי תועיל (הבטחתי).

הבדלים שטחיים:

  1. הפעולה __new__ נקראת לפני __init__.
  2. הפעולה __new__ מקבלת כפרמטר ראשון ייחוס למחלקה עצמה (cls), ולא למופע שנוצר ממנה (self).
  3. הפעולה __new__ מחזירה ערך.

נכניס להבדלים הללו מהות:

  1. בזמן הקריאה לפעולה __new__ המופע עדיין לא קיים, ולכן אי אפשר להתייחס ל־self.
  2. הערך ש־__new__ מחזירה הוא הוא המופע ש־__init__ תקבל לתוך ה־self שלה.
  3. אם __new__ רוצה, היא יכולה להחזיר מחרוזת, לדוגמה. במקרה כזה, במקום לקבל אובייקט מסוג cls תקבל אובייקט מסוג מחרוזת.

נראה דוגמה:

class Table:
    def __new__(self):
        return 'Hello!!'
    
Table()

יחזיר פשוט את המחרוזת 'Hello!!', במקום מופע מסוג Table.

דוגמה מעניינת לשימוש יכולה להיות בתבנית עיצוב שנקראת Singleton.
ב־Singleton, אנחנו רוצים שיצירת אובייקט פעם ראשונה תחזיר לנו מופע חדש (נקרא לו X), וניסיון ליצירת אובייקט בפעמים הבאות יחזיר את אותו X (לא מופע חדש).
זה שימושי, לדוגמה, אם אנחנו מתעסקים עם חיבורים ל־database: הרבה פעמים אנחנו רוצים לנהל רק חיבור אחד ל־database ולכן נרצה שקריאה למחלקה DatabaseConnection תחזיר תיצור פעם אחת חיבור למסד־הנתונים, ובפעמים הבאות פשוט תחזיר את החיבור שכבר נוצר.

נממש בעזרת __new__:

class DatabaseConnection:
    connection = None

    def __new__(cls, **kwargs):
        if cls.connection is not None:
            return cls.connection
        cls.connection = super().__new__(cls, **kwargs)
        return cls.connection
first_connection = DatabaseConnection()
second_connection = DatabaseConnection()
print(first_connection is second_connection)

True


בונוס:

בהרבה שפות יש משהו שנקרא Constructor, או בנאי. זו פונקציה של המחלקה שאחראית ליצור את האובייקט עצמו.
בספר Dive Into Python יש פסקה מעניינת שאומרת ככה:

הפעולה __init__() נקראת מייד אחרי שמופע של המחלקה נוצר. יהיה זה מפתה אך שגוי לקרוא [ל־__init__] הבנאי של המחלקה. זה מפתה, כיוון שהיא נראית כמו בנאי (כמוסכמה, __init__ היא הפעולה הראשונה המוגדרת עבור המחלקה), מתנהגת כאחד (זו חתיכת הקוד הראשונה שרצה כשיוצרים מופע מהמחלקה) ואפילו נשמעת כמו אחד (“init” ודאי רומז על טבע בנאי־י). שגוי, כיוון שהאובייקט כבר נבנה עד ש־__init__ נקראה, ויש לכם ייחוס למופע של המחלקה.

הדעות חלוקות האם הם צודקים והאם __init__ ראוי להיקרא בנאי או לא.

15 לייקים

האם new הוא הבנאי למעשה??

תודה איזה הסבר מציין !

3 לייקים

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

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

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

לייק 1

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

לייק 1