מה שכתוב בכותרת ועוד 20 תווים
שברתי על זה את הראש מול התיעוד כשעלו מתודות קסם בחומר.
מבחינה מעשית מה שהבנתי זה שnew מתבצע לפני init
מבחינת קונבנציה ושימוש מקובל, היה נראה שכל מיני מתבלבלים. אם הבנתי ואני זוכרת נכון, לא נהוג להשתמש בnew להענקת תכונות, לא ברור לי מה המצב שבו כדאי להתעסק עם new
.* יש מצב שיש הבדל גם בשימוש ב self בין השניים - כיוון ש new הוא יצירת המופע , ועבור init המופע כבר נוצר לפני
אז בעצם __init__
משתמשת ב-__new__
כדי ליצור את self?
אם כך, איזה שימושים פרקטיים יכולים להיות להגדרה מחדש של __new__
?
י. init זו פעולה שמתבצעת אחרי שהמופע כבר נוצר, היא פשוט נקראת אוטומטית אחרי יצירת המופע, כמו לכתוב:
Class()
self.init()
לא חייבים init במחלקה לצורך העיניין - לא רוצה להכנס כאן לעיניינים של מקובלות וכו’ (כי זה לא) - אבל מבחינת ביצוע נטו, לא חייבים להגדיר init : אם הייתי רוצה, הייתי יכולה להגדיר מחלקה בלי תכונות בכלל ויותר מאוחר לקרוא לפעולה בשם שמתחשק לי להוסיף תכונות (נדמה לי שככה זה בדוגמאות הראשונות במחברת, לא?).
init לא ‘משתמשת’ ב new , כי init מתחילה אחרי ש new כבר נגמרה.
לעומת זאת, אתה לא יכול ליצור מופע בלי new. פייתון יוצרת את המופע עם new . אתה תשנה את new אם אתה רוצה ליצור מופע בצורה אחרת ממה שפייתון עושה, וזה החלק שאני לא יודעת: מתי רוצים לעשות את זה.
עכשיו אני מבין, תודה!
אנסה לתת פה את ה־2 סנט שלי, עם דוגמה שאולי תועיל (הבטחתי).
הבדלים שטחיים:
- הפעולה
__new__
נקראת לפני__init__
. - הפעולה
__new__
מקבלת כפרמטר ראשון ייחוס למחלקה עצמה (cls
), ולא למופע שנוצר ממנה (self
). - הפעולה
__new__
מחזירה ערך.
נכניס להבדלים הללו מהות:
- בזמן הקריאה לפעולה
__new__
המופע עדיין לא קיים, ולכן אי אפשר להתייחס ל־self
. - הערך ש־
__new__
מחזירה הוא הוא המופע ש־__init__
תקבל לתוך ה־self
שלה. - אם
__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__
ראוי להיקרא בנאי או לא.
האם new הוא הבנאי למעשה??
תודה איזה הסבר מציין !
האמת הסבר ממש מעניין, יש הרבה דברים שלא קיימים ב פייתון אך יחסית נפוצים בשפות אחרות?
ברור.
כל שפת תכנות בוחרת את האופי שלה והרעיונות שהיא מממשת.
בכל שפה יהיו תכונות שסותרות תכונות של שפות אחרות, או תכונות שבשפות אחרות יש ובה אין.
יש את הדף הזה של השוואה, אבל הוא מחלק דברים בצורה די גסה.
לדעתי שווה לקרוא לעומק את הדף על שפות תכנות בוויקיפדיה. הוא כתוב ממש אחלה.
תודה, נתחיל להתעניין יותר נקווה שזה יעזור יותר להבין גם דרך לכתוב את הקוד