Why does python replace every object of a column, when only referring to one, if all lines are identical?

Question:

When trying to change one value in a matrix, python will change all items of that column with the desired value, despite the fact I am only trying to change one. But this only happens when all rows are identical.

Example:

def print_matrix(matrix: list[list], dlm: str) -> None:

    for row in matrix:

        for col in row:

            print(col, end = dlm)

        print()

        

one_row = list(range(4))

test_matrix = []

for i in range(5):

    test_matrix.append(one_row)

test_matrix[0][0] = 5

sec_matrix =[

    [0,1,2,3],

    [0,1,2,3],

    [0,1,2,3],

    [0,1,2,4]

]

sec_matrix[0][0]=5

print_matrix(test_matrix, ' ')

print()

print_matrix(sec_matrix, ' ')

In the first matrix every 0 gets replaced with a 5, despite only referencing the first item of the first list.
In the second one it works the way I want it to, because the last list is slightly different.
Why is there a difference in the way test_matrix and sec_matrix are treated? Is this a bug, or intended?
Does python just think they are the same list because they look the same?
Or are they even the same to increase performance? Either way I don’t think it should happen.

I tried to update a matrix item on certain coordinates.
I expected only the desired item to be altered, instead every single one of that column got changed. Problem is fixed by not having identical rows.

Asked By: rmm2908

||

Answers:

The reason is when you write test_matrix.append(one_row) you are appending actually [0,1,2,3] 5 times to test_matrix, essentially, i.e the list will look like [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]. Here each list element is a list with [0,1,2,3] references to the same [0,1,2,3]. When you then modify this single [0,1,2,3] it is visible via all references to it. For debugging purposes, you can check it,

print(id(test_matrix[0]))
print(id(test_matrix[1]))

So you will see all are the same id, if you want to do it then you can do it like below- where test_matrix = [ list(range(4)) for n in range(5) ] will re-generate value each time

def print_matrix(matrix, dlm):
    for row in matrix:
        for col in row:
            print(col, end = dlm)
        print()

    
test_matrix = []
test_matrix = [ list(range(4)) for n in range(5) ] # re-generate and appending

test_matrix[0][0] = 7
sec_matrix =[
    [0,1,2,3],
    [0,1,2,3],
    [0,1,2,3],
    [0,1,2,4]
]

sec_matrix[0][0]=5
print_matrix(test_matrix, ' ')
print()
print_matrix(sec_matrix, ' ')

Output:

7 1 2 3 
0 1 2 3 
0 1 2 3 
0 1 2 3 
0 1 2 3 

5 1 2 3 
0 1 2 3 
0 1 2 3 
0 1 2 4 
Answered By: Always Sunny
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.