ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ
Mutability and references
In lesson 1.1 you learned that a name refers to a value, like a tag hanging on it, not a box holding it. With lists, that difference explains bugs that confuse even experienced programmers. By the end of this lesson you'll predict them, and make a real copy when you need one.
Two names, one list
Predict what this prints.
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
a = [1, 2]
b = a
b.append(3)
print(a)Python prints
[1, 2, 3]
b = a doesn't copy the list; it gives the same list a second name. Appending through b changes that one list.
If you said [1, 2], you pictured b = a making a second list. Step through what
really happens: each arrow shows which value a name refers to.
Names and objects
Press Next to run one line at a time. Each arrow shows the object a name refers to.Each row is one step: the line that just ran, and the object each name refers to after it።
a refers to a list, [1, 2].
Step 1 of 4
Step 1 of 4. Line 1: a = [1, 2]. a now refers to a new list, [1, 2].
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 2 |
|
| 3 | 3 |
|
| 4 | 4 |
|
Python calls each value an
.
After line 2 there is one list object with two names on it. So the rule is: assignment
never copies. b = a means "b now refers to the object a refers to". The two names
aren't tied together; they just share one object. Now a subtle one:
ጥያቄ
After x = [1], then y = x, then y = [2], what is x?
Moving a name doesn't change the list
Press Next to run one line at a time. Each arrow shows the object a name refers to.Each row is one step: the line that just ran, and the object each name refers to after it።
x refers to a list, [1].
Step 1 of 3
Step 1 of 3. Line 1: x = [1]. x now refers to a new list, [1].
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 2 |
|
| 3 | 3 |
|
Changing an object and moving a name are different things. y.append(2) or y[0] = 2
would change the list, and x would see it. y = [2] only moves the name y.
The same object, or equal?
== asks "same value?". is (from lesson 2.4) asks "same object?". Here c is a
separate list with the same numbers:
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(a == c)
print(a is b)
print(a is c)In the editor, press Escape then Tab to move on.
Two equal lists are == but not is. Compare values with ==; keep is for None,
or for when you really mean "the same object".
Why numbers and strings never surprise you
Now the same shape of program with a string. Predict:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
s = "ab"
t = s
t += "c"
print(s)Python prints
ab
A string can't change, so t += "c" builds a new string, "abc", and moves t to it. s still refers to the original.
Names and objects
Press Next to run one line at a time. Each arrow shows the object a name refers to.Each row is one step: the line that just ran, and the object each name refers to after it።
s refers to a str, 'ab'.
Step 1 of 4
Step 1 of 4. Line 1: s = "ab". s now refers to a new str, 'ab'.
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 2 |
|
| 3 | 3 |
|
| 4 | 4 |
|
Strings and numbers can't change, so sharing one never surprises you: t += "c" and
n += 1 make new objects.
A list can change. Predict this one:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
a = [1, 2]
b = a
b += [3]
print(a)Python prints
[1, 2, 3]
On a list, += changes the list in place, like extend, and a refers to that same list.
+= on a list
Press Next to run one line at a time. Each arrow shows the object a name refers to.Each row is one step: the line that just ran, and the object each name refers to after it።
a refers to a list, [1, 2].
Step 1 of 4
Step 1 of 4. Line 1: a = [1, 2]. a now refers to a new list, [1, 2].
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 2 |
|
| 3 | 3 |
|
| 4 | 4 |
|
So b += [3] and b = b + [3] are not the same for lists: + builds a new list and
moves b to it. Run this, then change line 3 to b = b + [3] and run it again: a
stays [1, 2].
a = [1, 2]
b = a
b += [3]
print(a)In the editor, press Escape then Tab to move on.
The grid bug
You want a 3 by 3 grid of zeros, then set the top-left square to 1. Predict.
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
grid = [[0] * 3] * 3
grid[0][0] = 1
print(grid)Python prints
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
There's only one row, in the grid three times, so changing it shows in every row.
[row] * 3 doesn't copy the row. It makes a list whose three slots all refer to the
same row:
Names and objects
Press Next to run one line at a time. Each arrow shows the object a name refers to.Each row is one step: the line that just ran, and the object each name refers to after it።
grid refers to a list, [R1, R1, R1]: all 3 slots refer to one list, [0, 0, 0].
Step 1 of 2
Step 1 of 2. Line 1: grid = [[0] * 3] * 3. grid now refers to a new list, [R1, R1, R1]: all 3 slots refer to one list, [0, 0, 0].
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 2 |
|
[0] * 3 repeats the number 0 the same way, but numbers can't change:
grid[0][0] = 1 moves the row's slot 0 to a new number. The shared row is what changed.
The fix is a comprehension (lesson 4.7), which runs [0] * 3 again for every row. The
name _ is a convention for "a name I won't use":
grid = [[0] * 3 for _ in range(3)]
grid[0][0] = 1
print(grid)In the editor, press Escape then Tab to move on.
It's as if you wrote [0] * 3 three times. Step through and watch three separate
rows appear:
Three rows, three objects
Press Next to run one line at a time. Each arrow shows the object a name refers to.Each row is one step: the line that just ran, and the object each name refers to after it።
grid refers to a list, [].
Step 1 of 5
Step 1 of 5. Line 1: grid = []. grid now refers to a new list, [].
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 2 |
|
| 3 | 3 |
|
| 4 | 4 |
|
| 5 | 5 |
|
Making a real copy
When you do want a second list, ask for one: .copy() or list(...) both make a new
list with the same items.
a = [1, 2]
b = a.copy()
b.append(3)
print(a)
print(b)In the editor, press Escape then Tab to move on.
But what if the items are lists themselves? Predict:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
data = [[1, 2], 3]
backup = data.copy()
data[0].append(9)
print(backup)Python prints
[[1, 2, 9], 3]
.copy() makes a new outer list whose slots refer to the same objects. The inner list is shared, so backup sees the 9.
.copy() copies only the outer list: a
.
For a copy all the way down, use deepcopy from Python's copy module (imported like
random in lesson 3.5):
Names and objects
Press Next to run one line at a time. Each arrow shows the object a name refers to.Each row is one step: the line that just ran, and the object each name refers to after it።
Step 1 of 5
Step 1 of 5. Line 1: import copy. Nothing in memory changed.
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 | |
| 2 | 2 |
|
| 3 | 3 |
|
| 4 | 4 |
|
| 5 | 5 |
|
backup's slot 0 refers to the same inner list as data's. safe has its own inner
list, so the 9 never reaches it. (The 3 can't change, so sharing it is harmless.) Forget
the import and Python says what's missing:
The rule
One sentence covers all of it: assignment never copies; names refer to objects, and changing an object is seen through every name that refers to it. An object that can change is : lists, dicts, and sets. Numbers, strings, and tuples are immutable. This rule comes back in Module 5, where a list used as a function's default value surprises people.
መልመጃ
The backup that keeps changing
This program keeps a backup of the scores before adding a new one, but the backup changes too. Fix it so the backup keeps the old scores.
Your code
scores = [67, 82, 45]
backup = scores
scores.append(90)
print(backup)
print(scores)In the editor, press Escape then Tab to move on.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
scores = [67, 82, 45]
backup = scores.copy()
scores.append(90)
print(backup)
print(scores)ዋና ዋና ነጥቦች
- Assignment never copies:
b = agives the same object a second name. - Changing an object (
append,+=on a list,b[0] = ...) shows through every name; moving a name (b = [9]) doesn't. ==compares values;isasks whether two names refer to the same object.[[0] * 3] * 3repeats one row; build rows with a comprehension instead..copy()is shallow: inner lists are shared.copy.deepcopy()copies all the way down.