michaelmeyer
michaelmeyer

Reputation: 8205

Assignment rules

I've noticed a (seemingly) strange behaviour with assignments, which has led me several times to do programming mistakes.

See the following example first :

>>> i = 0
>>> t = (i,)
>>> t
(0,)
>>> i += 1
>>> t
(0,)

As expected, the value of the unique element of t does not change, even after the value of i has been incremented.

See now the following :

>>> l = [0]
>>> t = (l,)
>>> t
([0],)
>>> l[0] += 1
>>> t
([1],)  # <- ?

I don't understand why the initial zero in t is now one ; if I had incremented it with a reference to t...

>>> t[0][0] += 1

... I'd understand that it's value has changed, but this is not the case in the preceding example, where only l is explicitly referenced when incrementing.

I've got two questions:

  1. Why is it so?
  2. Are there special rules I should be aware of concerning this?

Upvotes: 5

Views: 308

Answers (2)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250961

That's because integers are immutable and lists are mutable.

>>> i = 0
>>> t = (i,)
>>> t[0] is i  # both of them point to the same immutable object
True
>>> i += 1  # We can't modify an immutable object, changing `i` simply 
            # makes it point to a new object 2.
            # All other references to the original object(0) are still intact.
>>> i
1
>>> t       # t still points to the same 0
(0,)
>>> x = y = 1
>>> id(x),id(y)
(137793280, 137793280)
>>> x += 1
>>> id(x),id(y)       #y still points to the same object
(137793296, 137793280)

for lists:

>>> l = [0]
>>> t = (l,)       
>>> t[0] is l #both t[0] and l point to the same object [0]
True
>>> l[0] += 1 # modify [0] in-place
>>> t
([1],)
>>> l
[1]
#another exmple
>>> x = y =[]    # x, y point to the same object
>>> x.append(1)  # list.append modifies the list in-place
>>> x, y          
([1], [1]) 
>>> x = x + [2]  # only changes x, x now points to a new object
>>> x, y
([1, 2], [1])

Upvotes: 8

mgilson
mgilson

Reputation: 309929

In the second example, t (the tuple) holds a reference to l (the list). When you do l[0] += 1, you're changing the list, but the tuple still holds a reference to the list. In the first example, when you do i += 1, you're actually creating a new integer which your tuple doesn't hold a reference to. See this answer that I wrote a while back for a much more in-depth explanation of the += operator and how it is actually implemented.

Upvotes: 2

Related Questions