The problem is here:
array_ab = [['?'] * 4] * 3
The problem is caused by the fact that python chooses to pass lists around by object reference. Because list is mutable object.
But since lists might get pretty large, rather than shifting the whole list around memory, Python chooses to just use a reference ('pointer' in C terms). If you assign one to another variable, you assign just the reference to it. This means that you can have two variables pointing to the same list in memory:
>>> a = [1]
>>> b = a
>>> a[0] = 2
>>> print b
[2]
So, in your first line of code you have ['?'] * 4
.
Now ['?']
is a pointer to the value ?
in memory, and when you multiply it, you get 4
pointers to the same place in memory.
BUT when you change one of the values then Python knows that the pointer needs to change to point to the new value:
>>> a = 4 * ['?']
>>> a
['?', '?', '?', '?']]
You can verify the id of the element inside the list:
>>> [id(v) for v in a]
[33302480, 33302480, 33302480, 33302480]
>>> a[0] = 1
>>> a
[1, '?', '?', '?']
The problem comes when you multiply this list - you get four copies of the list pointer.
Now when you change one of the values in one list, all four change together.
The suggested approach is to create a list of the desired length first and then fill in each element with a newly created list:
>>> A = [None] * 3
>>> for i in range(3):
... A[i] = [None] * 4
...
>>> A
[[None, None, None, None], [None, None, None, None], [None, None, None, None]]
>>>
This generates a list containing 3 different lists of length 4.
Or You can use list comprehension :
w, h = 4, 3
A = [[None] * w for i in range(h)]
[[None, None, None, None], [None, None, None, None], [None, None, None, None]]
Edit 2
Base on your header, you can't allocate a exact memory for list in advanced. Python list is using some kind of algorithm to over allocate the list size for future additional growth.
from the source code:
/* This over-allocates proportional to the list size, making room
* for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/