0

What different between [[0] * n for i in range(n)] and [[0] * n] * n]

I have this code:

def matrix_decomposition(a):
    n = len(a)
    b = [[0] * n for i in range(n)]
    c = [[0] * n for i in range(n)]
    for j in range(0, n):
        b[j][0] = a[j][0]
        c[0][j] = a[0][j]/b[0][0]
    for i in range(1, n):
        for j in range(1, i+1):
            b[i][j] = a[i][j] - sum(b[i][k]*c[k][j] for k in range(0, i))
        for j in range(i, n):
            c[i][j] = (a[i][j] - sum(b[i][k]*c[k][j] for k in range(0, i))) / b[i][i]
    return b, c

and if I replace [[0] * n for i in range(n)] on [[0] * n] * n I get this error:

Traceback (most recent call last): File "C:/Users/Noctus/PycharmProjects/lab3/matrix.py", line 46, in [7, 22, 70, 149] File "C:/Users/Noctus/PycharmProjects/lab3/matrix.py", line 27, in matrix_decomposition c[i][j] = (a[i][j] - sum(b[i][k]*c[k][j] for k in range(0, i))) / b[i][i] ZeroDivisionError: float division by zero

in 46 line I have:

b, c = matrix_decomposition([
        [1, 2, 3, 4],
        [2, 7, 21, 26],
        [4, 13, 43, 88],
        [7, 22, 70, 149]
])
Al.G.
  • 4,327
  • 6
  • 31
  • 56

2 Answers2

1

[[0]*n]*n returns a list of n references to the same list object [0,...,0] while [[0] * n for i in range(n)] returns a list of n references to n different objects (that happen to all be equal to [0,...,0]).

In the first case you cannot modify your rows independently since all your rows are essentially the same object, but in the second case all elements of your matrix can be independently modified.

Julien
  • 13,986
  • 5
  • 29
  • 53
1

You should never do anything like this [[0] * n] * n (multiplying a list with mutable objects inside), because multiplication on a list simply copies the references to its components. When you do [0] * n it creates a list of references to the same immutable object, hence you don't observe the side-effects of mutating the list in-place. At the same time, by doing [[0] * n] * n, you make n references to the same mutable list. Mutating it by one references mutates it everywhere.

>>> lst = [0] * 3
>>> lst
[0, 0, 0]
>>> lst[0] += 1
>>> lst
[1, 0, 0]
>>> lst = [[0] * 3] * 3
>>> lst
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> lst[0][0] += 1
>>> lst
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
Eli Korvigo
  • 10,265
  • 6
  • 47
  • 73
  • This is really neat! Super easy to implement, and understand. Nice work! –  Oct 22 '16 at 08:03