Quando scrivi [x]*3ottieni essenzialmente l'elenco [x, x, x]. Cioè, un elenco con 3 riferimenti allo stesso x. Quando poi modifichi questo singolo x, è visibile attraverso tutti e tre i riferimenti ad esso:
x = [1] * 4
l = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
f"id(l[0]): {id(l[0])}\n"
f"id(l[1]): {id(l[1])}\n"
f"id(l[2]): {id(l[2])}"
)
# id(l[0]): 140560897920048
# id(l[1]): 140560897920048
# id(l[2]): 140560897920048
x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"l: {l}")
# l: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]
Per risolverlo, devi assicurarti di creare un nuovo elenco in ogni posizione. Un modo per farlo è
[[1]*4 for _ in range(3)]
che rivaluterà [1]*4ogni volta invece di valutarlo una volta e fare 3 riferimenti a 1 elenco.
Potresti chiederti perché *non è possibile creare oggetti indipendenti come fa la comprensione dell'elenco. Questo perché l'operatore di moltiplicazione *opera su oggetti, senza vedere le espressioni. Quando si utilizza *per moltiplicare [[1] * 4]per 3, viene visualizzato *solo l'elenco a 1 elemento [[1] * 4], non il [[1] * 4testo dell'espressione. *non ha idea di come fare copie di quell'elemento, non ha idea di come rivalutare [[1] * 4], e non ha nemmeno idea di volerne copie, e in generale, potrebbe non esserci nemmeno un modo per copiare l'elemento.
L'unica opzione *è quella di fare nuovi riferimenti all'elenco secondario esistente invece di provare a creare nuovi elenchi. Qualsiasi altra cosa sarebbe incoerente o richiederebbe una riprogettazione importante delle decisioni fondamentali sulla progettazione del linguaggio.
Al contrario, una comprensione dell'elenco rivaluta l'espressione dell'elemento su ogni iterazione. [[1] * 4 for n in range(3)]rivaluta [1] * 4ogni volta per lo stesso motivo [x**2 for x in range(3)]rivaluta x**2ogni volta. Ogni valutazione di [1] * 4genera un nuovo elenco, quindi la comprensione dell'elenco fa quello che volevi.
Per inciso, [1] * 4inoltre, non copia gli elementi di [1], ma non importa, poiché i numeri interi sono immutabili. Non puoi fare qualcosa del genere 1.value = 2e trasformare un 1 in un 2.
[x]*3memorizzare 3 riferimenti come[x, x, x]è giusto solo quandoxè mutabile. Questo non funziona per esempioa=[4]*3, dove dopoa[0]=5,a=[5,4,4].