10

I've been using Python for some time already and today while reading the following code snippet:

>>> a = (1,2)
>>> a += (3,4)
>>> a
(1, 2, 3, 4)

I asked myself a question: how come python tuples are immutable and I can use an += operator on them (or, more generally, why can I modify a tuple)? And I couldn't answer myself.

I get the idea of immutability, and, although they're not as popular as lists, tuples are useful in python. But being immutable and being able to modify length seems contradictory to me...

ducin
  • 24,243
  • 40
  • 145
  • 253

3 Answers3

32

5 is immutable, too. When you have an immutable data structure, a += b is equivalent to a = a + b, so a new number, tuple or whatever is created.

When doing this with mutable structures, the structure is changed.

Example:

>>> tup = (1, 2, 3)
>>> id(tup)
140153476307856
>>> tup += (4, 5)
>>> id(tup)
140153479825840

See how the id changed? That means it's a different object.

Now with a list, which is mutable:

>>> lst = [1, 2, 3]
>>> id(lst)
140153476247704
>>> lst += [4, 5]
>>> id(lst)
140153476247704

The id says the same.

Veedrac
  • 54,508
  • 14
  • 106
  • 164
  • 1
    ok, so still I cannot add an element to an existing tuple (which makes it truly immutable), but a new object is created on basis of another two objects - is that right? – ducin Sep 25 '13 at 21:48
  • Just one thing is still not clear in your snippets. tuple::`+=` is using two tuples to create the third one, the result tuple. Seems like it;s different with list::`+=` - because it'd be logical if it would do the same (and create a third list). But `lst + [4,5]` actually makes append twice. Why doesn't `list::+=` follow `tuple::+=`? – ducin Sep 25 '13 at 21:53
  • Because a `list`'s `+=` is in-place. It's more "why doesn't `tuple` do what `list` does", and the answer is that "it can't". – Veedrac Sep 25 '13 at 21:54
  • I thought that `+=` operator works the same way for each sequence type. Or at least for tuples and lists. Thank you for explaining that it's totally different :). – ducin Sep 25 '13 at 21:57
  • @tkoomzaaskz: "Why doesn't list::+= follow tuple::+=" -- good question. For `list`, `a += b` is *not* equivalent to `a = a + b`. Some might consider that confusing, but they are probably not as confused, or not as frequently confused, as people would be if `list+=` *didn't* do an in-place append. Ultimately the issue is that the "inherent" equivalence between `a += b` and `a = a + b` holds when `a` and `b` have "value semantics". But Python variables don't have value semantics, they have reference semantics. That is to say, in Python a variable refers to an object, it doesn't contain a value. – Steve Jessop Sep 25 '13 at 22:39
6

Whether += modifies the object in-place or not is up to the object. With a tuple, you aren't modifying the object, as you can see if you create another variable pointing to the same object:

>>> x = (1, 2)
>>> y = x
>>> x += (3, 4)
>>> y
(1, 2)

With mutable objects such as lists, you will see that the value changes, showing up under all its names:

>>> x = [1, 2]
>>> y = x
>>> x += [3, 4]
>>> y
[1, 2, 3, 4]
BrenBarn
  • 228,001
  • 34
  • 392
  • 371
  • basing on your answer, the behavior of `+=` operator is based on mutable/immutable thing, and is in-place/not-in-place respectively. Thanks. – ducin Sep 25 '13 at 21:56
  • 1
    @tkoomzaaskz: Actually, the behavior of `+=` is up to each type. If a type defines an `__iadd__` method, Python will call that; otherwise, it will call `__add__` (the same method used for `+`) instead. Most immutable types don't define `__iadd__`, so `a += b` is the same as `a = a + b`; most mutable types _do_ define `__iadd__`, so it mutates them in-place. – abarnert Sep 25 '13 at 22:24
2

you are not modifying it, you created a new tuple and changed the content of the a variable

try a[0] = a[0] + 1 to see the immutability

prgao
  • 1,707
  • 14
  • 16