1

Say I have a list:

L = [1,2,3]

and I assigned L[0] to a variable a

a = L[0]

then if I change a, it won't affect L.

a = a + 1
print L # [1,2,3] not affected

Why is this happening? isn't python passing everything around with references? I thought that a is pointing to L[0]

shengy
  • 9,461
  • 4
  • 37
  • 61
  • Take a look to this answer http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference, I think there you can find the solution for your question, otherwise let me know – OscarG Sep 25 '13 at 06:29

4 Answers4

3

The problem is that a and L[0] are references to an immutable object, so changing any one of them won't affect the other references:

>>> L = [1, 2, [3]]
>>> a = L[0]
>>> a = a + 1

a now points to a new object, while L[0] still points to the same object.

>>> a, L[0]   
(2, 1)

Now in this case b and L[2] are references to a mutable object(list), any in-place operation on them will affect all the references:

>>> b = L[2]
>>> b.append(4)  #list.append is an in-place operation
>>> b, L[2]
([3, 4], [3, 4])

>>> b = b + [5]  #mutable object, but not an in-place operation 
>>> b            #b is assigned to new list object
[3, 4, 5]
>>> L[2]         #L[2] is unchanged
[3, 4]
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
2

L[0] is a name, and when you create the list L, you assign an object to that name, the integer 1. a is also a name, and when you assign a as in a = L[0], you make a to point to the same object that L[0] points to.

But when you later do a = a + 1, this is another assignment. You are not modifying the object that a points to -- the = sign can't do that. You are creating a new object, the integer 2, and assigning that to a.

So in the end, you have two objects in memory; one is referred to by L[0] and the other is referred to by a.

Integers are immutable, which means that there is no possible way to change the properties of the objects in this example; however, that's not salient in this example exactly, because even if the object was mutable it wouldn't change the fact that you're doing assignment (with the = sign). In a case where the object in question was mutable, you could theoretically change the properties of the object when it is still referenced by L[0] and a, instead of doing any additional assignment with = as you are doing. At that point, you would see the properties change regardless of which name you used to inspect the object.

Andrew Gorcester
  • 19,595
  • 7
  • 57
  • 73
  • I think it's not exactly accurate to say that `=` can't modify anything. While it's true that `L[0] = "foo"` replaces the old value in `L[0]` without modifying it, it does mutate the list `L`. – Blckknght Sep 26 '13 at 23:04
  • @Blckknght Thanks for pointing that out. It's not that `=` can't modify anything, because assignment can itself modify objects. But `=` can't modify the object referenced by the name it is operating on. It doesn't need to dereference the name itself at all --though in the case of `L[0]` or e.g. `obj.foo`, `L` or `obj` must be dereferenced in order to do the assignment. (If the name in question is a property, then there could be something tricky happening where the owner of the property is doing straight-up mutation in lieu of assignment, but that's a fairly advanced discussion topic.) – Andrew Gorcester Sep 26 '13 at 23:28
1

Since L[0] in your case is immutable, changing a doesn't affect the value of L[0]. When you change a, the new object is created and a starts to pointing to it.

See what happens if L[0] is of a mutable type:

>>> L = [[1],2,3]
>>> a = L[0]
>>> a.append(2)
>>> L
[[1, 2], 2, 3]

In this case a and L[0] both point to the same object.

Also see Raymond Hettinger's answer in the relevant thread.

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
0

Change the assignment to:

a = L

then when you change L as:

L[0] += 1

you will see that a also changes. This is the reference magic.

sureshvv
  • 4,234
  • 1
  • 26
  • 32