Search code examples
pythonoopattributes

python object attribute changing values


I was creating a grid (2 dimensional lists) of cell objects, in a nested loop. Immediately upon instantiating each cell, I have printed the values of their attributes. After exiting the loop, I loop through the cells again and re-print their attribute values. Some values seem unchanged (self.xlo), while some attributes seem to have been replaced by the attribute values (self.ylo, self.path) of the last cell. The 2 print statements are identical, and follow the same nested loop. Why are the results different?

mps = ['xxxxxx',
       'xoooox',
       'xoxxox',
       'xoooox',
       'xxxxxx']
ROWS = len(mps)     # equals 5
COLS = len(mps[0])  # equals 6
SCRW = 600
SCRH = 300
CELW = int(SCRW/COLS)
CELH = int(SCRH/ROWS)


class cell():
    def __init__(self, row, col, path):
        self.row = row
        self.col = col
        self.path = path
        self.xlo = int(col*CELW)
        self.ylo = int(row*CELH)
        return

row_blank = ['']*COLS
grid = [row_blank]*ROWS
path_list = []
for r in range(ROWS):
    for c in range(COLS):
        is_path = (mps[r][c]=='o')
        grid[r][c] = cell(r,c, is_path)
        print(f'cell {r},{c} position {grid[r][c].xlo},{grid[r][c].ylo} and path {grid[r][c].path}')
        
print("\n==============Re-Printing to check!")
for r in range(ROWS):
    for c in range(COLS):
        print(f'cell {r},{c} position {grid[r][c].xlo},{grid[r][c].ylo} and path {grid[r][c].path}')
    
exit()

Thanks for guidance - I seem to be making a very fundamental error with python OOP objects. Results of the print statements are below - the first set is correct , the re-print has changes.

cell 0,0 position 0,0 and path False
cell 0,1 position 100,0 and path False
cell 0,2 position 200,0 and path False
cell 0,3 position 300,0 and path False
cell 0,4 position 400,0 and path False
cell 0,5 position 500,0 and path False
cell 1,0 position 0,60 and path False
cell 1,1 position 100,60 and path True
cell 1,2 position 200,60 and path True
cell 1,3 position 300,60 and path True
cell 1,4 position 400,60 and path True
cell 1,5 position 500,60 and path False
cell 2,0 position 0,120 and path False
cell 2,1 position 100,120 and path True
cell 2,2 position 200,120 and path False
cell 2,3 position 300,120 and path False
cell 2,4 position 400,120 and path True
cell 2,5 position 500,120 and path False
cell 3,0 position 0,180 and path False
cell 3,1 position 100,180 and path True
cell 3,2 position 200,180 and path True
cell 3,3 position 300,180 and path True
cell 3,4 position 400,180 and path True
cell 3,5 position 500,180 and path False
cell 4,0 position 0,240 and path False
cell 4,1 position 100,240 and path False
cell 4,2 position 200,240 and path False
cell 4,3 position 300,240 and path False
cell 4,4 position 400,240 and path False
cell 4,5 position 500,240 and path False

==============Re-Printing to check!
cell 0,0 position 0,240 and path False
cell 0,1 position 100,240 and path False
cell 0,2 position 200,240 and path False
cell 0,3 position 300,240 and path False
cell 0,4 position 400,240 and path False
cell 0,5 position 500,240 and path False
cell 1,0 position 0,240 and path False
cell 1,1 position 100,240 and path False
cell 1,2 position 200,240 and path False
cell 1,3 position 300,240 and path False
cell 1,4 position 400,240 and path False
cell 1,5 position 500,240 and path False
cell 2,0 position 0,240 and path False

Process ended with exit code 0.

>

Solution

  • The problem lies in those 2 lines:

    row_blank = ['']*COLS
    grid = [row_blank]*ROWS
    

    When creating a list this way, you end up with "grid" containing several references to the same row object.

    The first print has "correct" values, because you print as you go. You assign initial values, print them, in the next iteration you assign new values and print them, and so on. If you separated assignments and printing the values, you'd see the problem there as well.

    You can check that with this code:

    for row in grid:
        print(id(row))
    

    which outputs (exact number is irrelevant, what matters is that it's the same number - which means same object):

    1714813861696
    1714813861696
    1714813861696
    1714813861696
    1714813861696
    

    Instead you should intitialise your grid like this, which ensures each row is a unique object.

    grid = [['' for _ in range(COLS)] for _ in range(ROWS)]