1

When I operate on two, I think equivalent multidimensional lists, I have different outcomes. The only difference between the lists is how they are created. I'm using Python 3.4.3

>>> b = [[1,2],[1,2]]
>>> b[0][0] += 1
>>> b
[[2, 2], [1, 2]]
>>> b = [[1,2]] * 2
>>> b
[[1, 2], [1, 2]]
>>> b[0][0] += 1
>>> b
[[2, 2], [2, 2]]

As you can see, both b's and the operations on them are the same, but the outcome is not. I'm guessing that it has something to do with the way they are created since that is the only difference, but I don't see how.

Its the same with Python 2.7.6

>>> b = [[1,2],[1,2]]
>>> b
[[1, 2], [1, 2]]
>>> c = [[1,2]] * 2
>>> c
[[1, 2], [1, 2]]
>>> c == b
True
>>> b[0][0] += 1
>>> b
[[2, 2], [1, 2]]
>>> c[0][0] += 1
>>> c
[[2, 2], [2, 2]]
>>> c == b
False
>>> 

3 Answers3

1
b = [[1,2],[1,2]]

print(id(b[0])) # 139948012160968
print(id(b[1])) # 139948011731400

b = [[1,2]]*2

print(id(b[0])) # 139948012161032
print(id(b[1])) # 139948012161032

`id() shows the object's ID or the memory location in Python.

When you do b = [[1,2]]*2 you are basically saying let's point to the same object twice and store it in b in a list.

When you do b = [[1,2],[1,2]] you are basically saying let me get two different objects and put them in a list and let b reference the list.

So for the latter example, of course you are going to get that output since they are the same object you are changing. You can think of it as me giving you the same address to a house and I have the same address I gave you. We end up at the same place and what ever changes we make to the house, we see it together.

Edited for comment:

Correct! They are changing how the memory is handled but the values are the same.

== tests if the values are the same. is tests if the objects are the same. so in our case:

#First case:
print(b[0] == b[1]) #true
print(b[0] is b[1]) #false

#second case:
print(b[0] == b[1]) #true
print(b[0] is b[1]) #true

Edited second time for second comment!~

import copy
x = [1,2]
b = [copy.copy(x) for i in range(3)]
print(id(b[0])) #140133864442248
print(id(b[1])) #140133864586120
print(id(b[2])) #140133864568008
print(b) #[[1, 2], [1, 2], [1, 2]] you can extend range to 256. 

If you want a unique object and want to copy it from another object, try using copy. It makes a new object with the same values.

Edited again using one of my favorite function sum:

This is more or less redundant and it might confuse you some more, but sum also works too.

 x = [1,2]
 b = [sum([x],[]) for i in range(3)]
 print(id(b[0])) #140692560200008
 print(id(b[1])) #140692559012744
 print(b) #[[1, 2], [1, 2], [1, 2]]

Will return different instances in the object. I only point this is just in case you don't want to import copy or import anything.

MooingRawr
  • 4,901
  • 3
  • 24
  • 31
  • Thanks! So the lists are equivalent, but not how the data is handled in memory? I'm refering in particular to the second piece of code where it says b == c True – Piepongwong Oct 04 '16 at 15:26
  • so how do I get a list of, lets say, 256 times [1,2] and different references? – Piepongwong Oct 04 '16 at 15:31
  • Correct! see the edited answer for the first question and second comment! Hope it make sense. – MooingRawr Oct 04 '16 at 15:33
0

This is very-well understood behavior in Python.

a = [[], []] # two separate references to two separate lists
b = [] * 2 # two references to the same list object
a[0].append(1) # does not affect a[1]
b[0].append(1) # affects b[0] and b[1]
Graham
  • 7,431
  • 18
  • 59
  • 84
Logan Byers
  • 1,454
  • 12
  • 19
0

In the second case you're making what's known as a shallow copy of the [1,2] list. Essentially what that means is that somewhere in memory you have the list [1,2], and when you write [[1,2]]*2 you're saying you want two references to that same list. Thus, when you change one of the lists, you're actually changing the list that both items in b are referring to.

chukrum47
  • 81
  • 3