1

So i was trying to recreate game of life in python using a 2 dimensional array, but i stumbled into a really weird bug. To make the array i made this function:

def MakeGrid(height):
    gridY = []
    grid = []
    for i in range(height):
        gridY.append(False)
    for i in range(height):
        grid.append(gridY)
    return(grid)

But there is a really weird bug where if i try to change a False into a True in only 1 spot, it changes everywhere diagonally. Here's an example:

grid = MakeGrid(2) # grid is now [[False,False], [False,False]]
grid[0][0] = True #grid should be [[True, False], [False, False]], but it's actually [[True, False], [True, False]]

I really don't know what causes this but it's really annoying me and i would really love some help.

Gamer Rat
  • 19
  • 2
  • 3
    try `grid.append(gridY.copy())` and read https://www.python-course.eu/python3_deep_copy.php – Epsi95 Aug 24 '21 at 09:47
  • Both lists point to the same object in memory since you appended `gridY` `height` number of times. Hence changing one element in `gridY` changes that element for all lists pointing to `gridY`. – ChrisOram Aug 24 '21 at 09:49

3 Answers3

2

It's not a bug, but rather the intended behavior when appending the exact same list over and over again. Since the you're appending the same list (gridY) into grid, they all share the same memory inside of grid; meaning that a change in one element (or more) in any of the lists inside of grid will apply to all other lists inside of grid since they're the same object.

Look at the following:

x = [1, 2, 3]
y = []
y.append(x)
y.append(x)
y[0] == x  # True (same list contents)
y[0] is x  # Also True! (same memory, exact same list)

Thus you would need to append a copy of that list, that doesn't share the same memory/identity, but the same contents using .copy()

Omar AlSuwaidi
  • 1,187
  • 2
  • 6
  • 26
0

What is happening is grid array is storing many pointers to the same gridY part in the memory. When you change one pointer, the whole gridY changes. So when you change one False in gridY to True, the whole gridY changes. You could use

def MakeGrid(height):
    gridY = []
    grid = []
    for i in range(height):
        gridY.append(False)
    for i in range(height):
        grid.append(gridY[:])
    return(grid)

or

def MakeGrid(height):
    gridY = []
    grid = []
    for i in range(height):
        gridY.append(False)
    for i in range(height):
        grid.append(gridY.copy())
    return(grid)

as @Epsi95 mentioned

Sarvesh M.D
  • 192
  • 1
  • 11
0

It is an aliasing problem. A list is an Object in python, and here you have decelerated gridY as a list object and are constantly changing it. By appending it constantly to grid you are not creating new objects of different length but are adding the same object multiple times. When you try to change in once, you are changing it throughout grid

Ofek Glick
  • 999
  • 2
  • 9
  • 20