0

I have the following code:

matrix = [[0] * 3] * 3
matrix[0][0] = 2

I want to get the following result:

[[2, 0, 0], [0, 0, 0], [0, 0, 0]]

However it changes the first element of each sublist and returns this list:

[[2, 0, 0], [2, 0, 0], [2, 0, 0]]

If I define matrix as follow:

matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

then it works.

Could anyone tell me please, why it happens and how could solve this problem?

Thanks

Marius
  • 58,213
  • 16
  • 107
  • 105
John
  • 429
  • 3
  • 8
  • 20
  • 1
    List multiplication over mutable objects creates copies of the reference to the objects, not distinct objects. http://docs.python.org/2/faq/programming.html#how-do-i-create-a-multidimensional-list – Peter DeGlopper Dec 03 '13 at 00:14
  • 1
    This is a pretty FAQ ... The solution is to use a list comprehension `[[0]*3 for _ in range(3)]` – mgilson Dec 03 '13 at 00:14
  • You might also want to consider using a multidimensional array type or matrix type, like a [NumPy](http://www.numpy.org) `ndarray` or `matrix`, instead of a list of lists. (Even if you're only doing this for learning purposes, learning how to build something that acts like a simple version of `np.matrix` is a great way to start…) – abarnert Dec 03 '13 at 00:29

3 Answers3

1

This is happening because [[0] * 3] * 3 is actually creating an array of 3 of the same object (the [0] * 3 array). One way of looking at it is that the inner array is created once and copied. An alternative would be to use [[0] * 3 for x in xrange(3)], as this executes [0] * 3 each iteration in list comprehension, creating a new array each time.

Sean
  • 4,450
  • 25
  • 22
0

Python assigns by pointer rather than value* which sometimes leads to undesirable results such as this one. Here is a tutorial that explains what is really happening: http://www.python-course.eu/variables.php Here is one possible fix http://www.python-course.eu/deep_copy.php

*(as has been pointed out this is not quite right, however it similar in result to what happens in other languages like C which I'm more familiar with if you passed a pointer to a variable rather than a copy of the value of the variable.)

Troy Rockwood
  • 5,875
  • 3
  • 15
  • 20
  • amaizing, thanks indeed to all for your prompt answers and explainations and solutions. – John Dec 03 '13 at 00:29
  • "Python assigns by pointer" is a really misleading way to put this. Jython and PyPy certainly don't assign any pointers, given that they're written in languages (Java and (R)Python that don't have pointers… – abarnert Dec 03 '13 at 00:30
  • Actually Java is almost all pointers. Any variable with a reference type is really just a pointer in disguise. If Java had a similar syntax for this it would have the same issue. – Sean Dec 03 '13 at 00:36
  • now I have a further question: why are the elements of the sublists not copies of the same object although you create the sublist-elements also by multiplication? After running these two lines matrix = [[0] * 3 for x in xrange(3)] matrix[0][0]=2 I'd expect this result:[[2,2,2], [0,0,0], [0,0,0]]. Why I'm wrong with my thought? – John Dec 03 '13 at 13:29
  • I think, I got it: maybe the reason is, because the elements of sublists are of int type, so they are immutable and get created as new objects and not as reference to the same object as with lists. – John Dec 03 '13 at 13:39
0

Here's your problem, matrix, in this example, is basically identical to:

>>> a = [0,0,0]
>>> matrix1 = [a,a,a]

that means when you do matrix1[0][0] = 2, what Python does is follow its pointer located at the first index of matrix1, which points to object a, then looks at the pointer located at the first index of a, which reads 0, then changes that to 2. Then when you ask it to evaluate matrix1, it looks up a three times and finds [2,0,0] each time.

Sean had a good solution above mine, using list comprehensions to force new objects instead of adding pointers for objects that already exist. That may serve you better :)

Community
  • 1
  • 1
Adam Smith
  • 52,157
  • 12
  • 73
  • 112