7
myVar = ["jhhj", "hgc"]
myTuple = ([1,2,3], [4,5,6], myVar)
myVar.append('lololol')
print myTuple

Why and how can this tuple be modified by appending after construction?

myVar = "lol"
myTuple = ([1,2,3], [4,5,6], myVar)
myVar = "lolol"
print myTuple

Why is this going to print out ([1,2,3], [4,5,6], "lol") instead of ([1,2,3], [4,5,6], "lolol")?

brandizzi
  • 26,083
  • 8
  • 103
  • 158
Web Master
  • 4,240
  • 6
  • 20
  • 28

6 Answers6

7

Well, let me try to explain with some images.

In Python, everything is an object. Those objects are referenced by variables. Some kinds of objects, such as lists and tuples, just store references to other objects.

That said, when you execute

myVar = ["jhhj", "hgc"]
myTuple = ([1,2,3], [4,5,6], myVar)

You get more or less this scenario:

A tuple pointing to three lists; a list pointing to two strings

Each object is represented by a box/rectangle. We have two string objects, "jhhj" and "hgc". Also, we have a list object, pointed by the variable myVar; this list object points to both string objects. Also, we have a tuple object, referenced by myTuple; this tuple object points two other lists and the list referenced by myVar.

When you execute

myVar.append('lololol')

what does happen? Well, the list object (that is incidentally pointed by myVar) starts to referenced one more value, the string object "lololol":

A tuple pointing to three lists; a list pointing to two strings; a new string is added to the list

Note that myVar still references the list object. What happened is that the list object changed. You can look at this list object both from myVar or from the tuple, you will see the same object with the same change.

OTOH, when you execute

myVar = "lol"
myTuple = ([1,2,3], [4,5,6], myVar)

You get something like this:

A tuple pointing to two lists and a string, also pointed by a variable

Now myVar points to the string object "lol", as well the tuple references it at its third position. Now, if you execute

myVar = "lolol"

you are just making myVar to point to another object. The tuple object still points to "lol" as before:

A tuple pointing to two lists and a string, also pointed by a variable. The variable now references another string.

So, if you attribute a new value to a variable, it will just change the value pointed by this variable. The previous value referenced by the variable will still exist* and any other variable or object pointing to it will stay pointing to it. Just the attributed variable will change.

PS: Also, I answered a vaguely related question some time ago. You may find the answer helpful.

* Except if it is collected by the garbage collector, but this is another long history.

Community
  • 1
  • 1
brandizzi
  • 26,083
  • 8
  • 103
  • 158
5

All things in python are objects.

So when you do your original assignment

myVar = "lol"

you are giving myVar a reference to the object "lol"

You then create a tuple. This tuple in the third slot has a reference to "lol"

Then you create a new object "lolol" and give myVar a reference to it. The tuple retains its original reference to "lol"

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
  • so how come appending a list later in the program modifies the original tuple? – Web Master Jun 14 '12 at 02:54
  • You are modifying the list object inside the tuple – anthony sottile Jun 14 '12 at 02:58
  • 1
    You're not modifying the tuple. You're modifying the list members of a tuple. A slightly inaccurate, but helpful way to look at it is that a tuple `([1,2], [3,4])` is really `(address_to_list1, address_to_list2)` You can't change the addresses, but the lists are separate, mutable objects. – Joel Cornett Jun 14 '12 at 02:58
1

Tuples are immutable, so you would need to construct a new tuple if you wanted to modify one of its members...

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
1

Tuples are immutable but you can concatenate them together like :

var a = (1, 2)
var b = a + (3, 4)
Phu
  • 572
  • 3
  • 10
1

In both cases, when you create the tuple you're copying a reference to whatever object myvar was at the time.

In the first case, myvar is a mutable object. You can change the object after a reference to it has been stored in the tuple.

In the second case, myvar is an immutable string. You can't change the object, but you can change what myvar itself refers to. That doesn't change the object that is contained within the tuple though.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
1

There have been some great points in other answers that I won't re-iterate yet again, explaining the difference between names and objects. All I think is missing is spelling out when some Python code is operating on names and when it is operating on objects.

A key thing that you need to understand though is that the only thing that affects names directly is assignment statements[1]. An assignment statement rebinds the name to point to a different object. A name appearing in any other context is just a simple standing for whatever object the name is bound to when that line of code is executed.

Lets look at this line from your example:

myTuple = ([1,2,3], [4,5,6], myVar)

myTuple appears on the left side of the assignment statement, so the name myTuple is what's being affected there. myVar on the other hand is inside an expression, so it's the object myVar is bound to that is the third element of the tuple, not the name myVar.

Consequently, whatever happens later to the name myVar has no effect whatsoever on the tuple. But as long as the third element of the tuple and myVar refer to the same object, changing that object (through either myVar or the tuple) will obviously affect what you get when you look at the object through either reference.


[1] For advanced study, def and class statements are also "assignment statements" (they create a function or a class and then assign it to the name).

Also, operators like +=, *=, etc are sometimes assignment statements and sometimes not, depending on the type of the object currently referred to by the name on the LHS:

myList = []
myList += ['this calls a method on a list object which mutates it in place; the name is not changed']

myInt = 1
myInt += 10  # This rebinds myInt to refer to a new object 11; the object 1 is not changed
Ben
  • 68,572
  • 20
  • 126
  • 174