4

Take the following code for example:

t=(1,2,3)
t+=(4,)
print(t)

The printed value is (1,2,3,4).Didn't the value of tuple t just got changed which is similar to an append/extend method for list objects?

Oliver H
  • 65
  • 1
  • 7

4 Answers4

5

You can concatenate tuples into a new tuple. You're replacing the value of t entirely with a new value. You cannot modify an existing tuple. To illustrate:

t = (1, 2, 3)
u = t
t += (4,)  # shorthand for t = t + (4,)

t == u  # False
t is u  # False

t and u do not refer to the same object anymore.

With mutable data structures, that would not be the case:

t = [1, 2, 3]
u = t
t.append(4)

t == u  # True
t is u  # True
deceze
  • 510,633
  • 85
  • 743
  • 889
  • 3
    Note that the implementation of the `+=` operator on lists and tuples is very different. On lists, `+=` mutates the left hand operand list, so you can use that instead of `append` in the second example as well. – Håken Lid Oct 10 '18 at 09:57
3

Tuples are immutable. That is they can not be changed like lists in python. What you are doing is, just replacing old tuple with new tuple.

elpidaguy
  • 624
  • 1
  • 11
  • 25
3

t += (4,) is more or less syntactical sugar. It translates to

t = t.__iadd__((4,))

(assuming this method exists. If it doesn't, it falls back to t = t + (4,)). Since tuples are immutable, at best __iadd__ would return a new tuple that gets bound to the old name t. For lists in a similar setting the returned list would be the (mutated) original.

0

What you are doing is re-assignment of a new tuple object to the variable t. You are not modifying the same object.

Let's start disassembling the code..

See this (Notice STORE_FAST in second block (85)):

import dis

def tup_concat():
    t = (1, 2, 3)
    t += (4,)
    print(t)                             

 84           0 LOAD_CONST               1 ((1, 2, 3))
              2 STORE_FAST               0 (t)

 85           4 LOAD_FAST                0 (t)
              6 LOAD_CONST               2 ((4,))
              8 INPLACE_ADD
             10 STORE_FAST               0 (t)

 86          12 LOAD_GLOBAL              0 (print)
             14 LOAD_FAST                0 (t)
             16 CALL_FUNCTION            1
             18 POP_TOP
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE                          

However, if you truly modify an object (say list) it would look something like this:

import dis

def modify():
    t = [4,6,7]
    t.append(4)

dis.dis(modify)           

 89           0 LOAD_CONST               1 (4)
              2 LOAD_CONST               2 (6)
              4 LOAD_CONST               3 (7)
              6 BUILD_LIST               3
              8 STORE_FAST               0 (t)

 90          10 LOAD_FAST                0 (t)
             12 LOAD_METHOD              0 (append)
             14 LOAD_CONST               1 (4)
             16 CALL_METHOD              1
             18 POP_TOP
             20 LOAD_CONST               0 (None)
             22 RETURN_VALUE                            

Notice: There is no STORE_FAST in second block (90).

Conclusion: It does not refer to the same object (variable t before and after INPLACE_ADD).

BlackBeard
  • 10,246
  • 7
  • 52
  • 62