The concept that matters here is the idea of referencing. In Python, variables are references to objects that sit somewhere in memory. Let's use the an arrow → to indicate a reference. Variable → Object. Variable on the left, object on the right.
The array can be visualized as three variables that reference three integer objects.
a[0] → int(1)
a[1] → int(2)
a[2] → int(3)
Now, integer objects are immutable. They can't be changed. When you change an integer variable you're not changing the object the variable refers to. You can't, because int
s are immutable. What you can do is make the variable reference a different object.
Direct update
Let's look at the second loop first since it's simpler. What happens if you update the array directly?
for i in range(0, len(a)):
a[i] += 1
First let's unroll the loop:
a[0] += 1
a[1] += 1
a[2] += 1
For integers, a[0] += 1
is equivalent to a[0] = a[0] + 1
. First, Python evaluates a[0] + 1
and gets the result int(2)
. Then it changes a[0]
to reference int(2)
. The second and third statements are evaluated similarly.
a = [1, 2, 3] # a[0] → int(1)
# a[1] → int(2)
# a[2] → int(3)
a[0] += 1 # a[0] → int(2)
a[1] += 1 # a[1] → int(3)
a[2] += 1 # a[2] → int(4)
Indirect update
And what about what I'll call "indirect" updating?
for x in a:
x += 1
Unrolling the loop yields this equivalent series of statements:
x = a[0]
x += 1
x = a[1]
x += 1
x = a[2]
x += 1
What happens at each step, and why isn't the array changed?
x = a[0]
This makes x
reference whatever object a[0]
references. Both a[0]
and x
reference the same int(1)
object, but x
isn't directly connected to a[0]
. It refers to whatever a[0]
refers to, not to a[0]
itself.
x += 1
This changes what x
refers to. It has no effect on a[0]
.
The same thing happens for the second and third assignments. The result is that x
is continually changed while the elements of a
are merely read from but never modified. And so when the loop terminates a
is unchanged.
a = [1, 2, 3] # a[0] → int(1)
# a[1] → int(2)
# a[2] → int(3)
x = a[0] # x → int(1)
x += 1 # x → int(2)
x = a[1] # x → int(2)
x += 1 # x → int(3)
x = a[2] # x → int(3)
x += 1 # x → int(4)