ניתן לשינוי ושאינו ניתן לשינוי בפייתון

ניתן לשינוי ושאינו ניתן לשינוי בפייתון

מאמר זה מסביר מהו ניתן לשינוי ושאינו ניתן לשינוי בפייתון.

YouTube Video

ניתן לשינוי ושאינו ניתן לשינוי בפייתון

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

מהו ניתן לשינוי?

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

סוגי נתונים עיקריים שניתן לשנותם

  • list
  • dict
  • set
  • כיתות שהוגדרו על ידי המשתמש (אם ניתן לשנות את התכונות שלהן)

דוגמה: שינוי רשימה

1numbers = [1, 2, 3]
2numbers[0] = 100
3print(numbers)  # [100, 2, 3]

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

מהו שאינו ניתן לשינוי?

אובייקטים שאינם ניתנים לשינוי אינם ניתנים לשינוי לאחר יצירתם. ניסיון שינוי שלהם יגרום ליצירת אובייקט חדש.

סוגי נתונים עיקריים שאינם ניתנים לשינוי

  • int
  • float
  • str
  • tuple
  • bool
  • frozenset

דוגמה: שינוי מחרוזת

1text = "hello"
2# text[0] = "H"  # TypeError: 'str' object does not support item assignment
3
4text = "H" + text[1:]  # Creates a new string
5print(text)  # "Hello"

מחרוזות אינן ניתנות לשינוי, ולכן לא ניתן לשנות אותן באופן חלקי.

השוואה בין ניתן לשינוי ושאינו ניתן לשינוי

 1# Mutable example
 2a = [1, 2, 3]
 3b = a
 4b[0] = 100
 5print(a)  # [100, 2, 3] -> a is also changed
 6
 7# Immutable example
 8x = 10
 9y = x
10y = 20
11print(x)  # 10 -> x is unchanged

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

בדיקת התנהגות פנימית באמצעות id()

ב-Python, ניתן להשתמש בפונקציה id() כדי לבדוק את מזהה האובייקט. המזהה של האובייקט דומה לכתובת זיכרון.

 1# Immutable int behavior
 2a = 10
 3print(id(a))  # e.g., 140715920176592
 4a += 1
 5print(id(a))  # e.g., 140715920176624 -> ID has changed
 6
 7# Mutable list behavior
 8b = [1, 2, 3]
 9print(id(b))  # e.g., 2819127951552
10b.append(4)
11print(id(b))  # Same ID -> only the content has changed

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

פונקציות וזהירות עם אובייקטים ניתנים לשינוי ובלתי ניתנים לשינוי

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

דוגמה: פונקציה שמשנה רשימה

1def modify_list(lst):
2    lst.append(100)
3
4my_list = [1, 2, 3]
5modify_list(my_list)
6print(my_list)  # [1, 2, 3, 100]

דוגמה: פונקציה שמשנה מספר

מצד שני, ניסיון לשנות אובייקט בלתי ניתן לשינוי יוביל ליצירת אובייקט חדש.

1def modify_number(n):
2    n += 10
3
4my_number = 5
5modify_number(my_number)
6print(my_number)  # 5 -> unchanged

שיקולים פרקטיים

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

 1# Bad example
 2def add_item(item, container=[]):
 3    container.append(item)
 4    return container
 5
 6print(add_item(1))  # [1]
 7print(add_item(2))  # [1, 2] -> unintended behavior
 8
 9# Good example
10def add_item(item, container=None):
11    if container is None:
12        container = []
13    container.append(item)
14    return container

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

סיכום

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

תוכלו לעקוב אחר המאמר שלמעלה באמצעות Visual Studio Code בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.

YouTube Video