Quando scrivi [x]*3
ottieni 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]*4
ogni 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] * 4
testo 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] * 4
ogni volta per lo stesso motivo [x**2 for x in range(3)]
rivaluta x**2
ogni volta. Ogni valutazione di [1] * 4
genera un nuovo elenco, quindi la comprensione dell'elenco fa quello che volevi.
Per inciso, [1] * 4
inoltre, non copia gli elementi di [1]
, ma non importa, poiché i numeri interi sono immutabili. Non puoi fare qualcosa del genere 1.value = 2
e trasformare un 1 in un 2.
[x]*3
memorizzare 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].