Creating a two-dimensional array in Python

I was building a two-dimensional vector in Python, and since I wanted it to be zero first and not want to use numpy, I tried this:

columns = 8 rows = 5 m = [[0]* (columns)] * (rows) m[3][2] = 1 print m 

And I got unexpected behavior:

 >> [[0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0]] 

It looks like creating a two-dimensional array, like this, makes each line a link to one line, so if you write in any of them, you write over all of them.

It may seem obvious to some of you, but I laughed a little. Of course, I can fix this using a different approach, but I wonder why this is happening.

Can anyone explain? Why doesn't this happen if you create a simple array with [0] * size_of_array ?

+4
source share
3 answers

This is a common goth in Python. You do not create internal lists of rows , you create links of rows for the same list.

Your code is equivalent to the following:

 inner_list = [0] * columns m = [inner_list] * rows 

I would recommend building strings without using the * operator. (You did not encounter a problem with columns, since 0 is int and ints are immutable objects.)

 matrix = [] for row in rows: matrix.append([0] * columns) 
+5
source

[0] * size_of_array creates a list that contains several references to 0 . If you put a different value on this list, it will not be affected.

As you noticed, [[]] * num creates a list that contains a link to the same list again and again. Change this list, the change is visible on all links.

 >>> a = [0] * 10 >>> [id(i) for i in a] [31351584L, 31351584L, 31351584L, 31351584L, 31351584L, 31351584L, 31351584L, 31351584L, 31351584L, 31351584L] >>> >>> all(i is a[0] for i in a) True 

vs.

 >>> a = [[]] * 10 >>> a [[], [], [], [], [], [], [], [], [], []] >>> [id(i) for i in a] [44072200L, 44072200L, 44072200L, 44072200L, 44072200L, 44072200L, 44072200L, 44072200L, 44072200L, 44072200L] >>> all(i is a[0] for i in a) True 

In the same situation, but one thing is different:

If you execute a[0].append(10) , the effect is displayed in all lists.

But if you do a.append([]) , you add a clean new list that is not related to others:

 >>> a = [[]] * 10 >>> a [[], [], [], [], [], [], [], [], [], []] >>> a.append([]) >>> a[0].append(8) >>> a [[8], [8], [8], [8], [8], [8], [8], [8], [8], [8], []] >>> a[-1].append(5) >>> a [[8], [8], [8], [8], [8], [8], [8], [8], [8], [8], [5]] 
+2
source

When you do [[0] * 8] * 5, it does not create a list containing 5 links to new objects. First, it creates an object [0] * 8 (list), then assigns a link to this single list to each element created * 5.

This is equivalent to:

 a = [ 0 ] * 8 b = [ a ] * 5 
+1
source

Source: https://habr.com/ru/post/1489532/


All Articles