פייתון/פייתון גרסה 3/העתקים

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי

העתקים היא פעולה שמייצרת העתקה של טיפוסים. קיימים שני סוגים של העתקים:

  1. העתק עמוק (deep copy) - למשתנה המועתק יש מיקום זיכרון משל עצמו. שינויים שבוצעו על המשתנה לא ישפיעו על המקור.
  2. העתק רדוד (shallow copy)- המשתנה החדש "מצביע" (alias) אל אותו תא זיכרון של המשתנה המקורי ועל כן שינוים במשתנה החדש ישפיעו על המשתנה המקורי. לדוגמה השמה מייצרת העתק רדוד.
  • בכדי לדעת האם מדובר בהעתק עמוק או רדוד נעזר בפונקציית id שמחזירה את "מקום הזיכרון".

פונקצית id[עריכה]

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

a=[1,2,3]
x=a
print(id(x))
print(id(a))
x.append(4)
print(a)
>>>2414993751560
>>>2414993751560
>>>[1, 2, 3, 4]

לעומת זאת הצהרה מייצרת בדיוק את אותו רשימה אך היא נשמרת במקום חדש:

x=[1,2,3]
y=x[:]
print(id(x))
print(id(y))
y.append(1)
print(x)
print(y)

>>>2123513615304
>>>2123477079176
>>>[1, 2, 3]
>>>[1, 2, 3, 1]

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

רשימה[עריכה]

העתקים מייצרים העתק רדוד לרשימות כלומר מייצר מצביע לאותה. נראה את ההשפעה של העתקים על רשימות : נשם לב לקריאות הבאות:

>>> num = 2
>>> L = [num] * 3
>>> L
[2, 2, 2]
>>> L[2] = 3
>>> L
[2, 2, 3]

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

>>> num = 2
>>> L2 = [[num] ] * 3
>>> L2
[[2], [2], [2]]
>>> L2[1][0] = 10
>>> L2
[[10], [10], [10]]

# same to...
>>> nest_lst = [num]
>>> L2 = [nest_lst]*3
>>> L2
[[2], [2], [2]]
>>> L2[1][0] = 9
>>> L2
[[9], [9], [9]]

במקרה השני יצרנו העתק רדוד לרשימה מקוננת ולכן כאשר שיננו את הרשימה המקוננת (בדוגמה השנייה nest_lst) כל הרשימות שהצביעו אליה השתנו.

>>> num = 2
>>> L3 = [[num]*4]*2
>>> L3
[[2, 2, 2, 2], [2, 2, 2, 2]]
>>> L3[1][0] = 5
>>> L3
[[5, 2, 2, 2], [5, 2, 2, 2]]

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

רשומה[עריכה]

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

tpl=(1,2,3)
tpl=tpl+(123,)
print(tpl)
>>>(1, 2, 3, 123)

ההבדל בין אופרטור == לעומת is [עריכה]

#Declaration - creates a new variables
>>> a=400
>>> b=400
>>> id(a)
89043264
>>> id(b)
89043920

# == vs is 
>>> a==b
True
>>> a is b
False

# Assigning
>>> x=23423
>>> y=x
>>> id(x)
103332672
>>> id(y)
103332672

# == vs is 
>>> x is y
True
>>> x ==y
True

#comparing list:

x=[1,3,2]
y=x[:] #deep copy
z=x # assigning

print(x is y) # Flase - "is" cheacks if 'x' and 'y' has the same location in the memory
print(x is z) #true
print(x==y) #true - cheacks if the values of x,y are the same!

כלומר, אופרטור is בודק האם שני משתנים רשומים באותו מקום בזיכרון, ו-== בודק האם הערך שווה

הערה[עריכה]

שמו לב שפייתון מאחסנת מספרים נמוכים באותה כתובת ולכן עלולים להתבלבל בין סוגי העתקים:

>>> a=1
>>> b=1
>>> id(a)
1573705520
>>> id(b)
1573705520
>>> a==b
True
>>> a is b
True