Lorsque vous écrivez, [x]*3
vous obtenez, essentiellement, la liste [x, x, x]
. Autrement dit, une liste avec 3 références à la même chose x
. Lorsque vous modifiez ensuite ce single, x
il est visible via les trois références:
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]]
Pour y remédier, vous devez vous assurer de créer une nouvelle liste à chaque position. Une façon de le faire est
[[1]*4 for _ in range(3)]
qui réévaluera à [1]*4
chaque fois au lieu de l'évaluer une fois et de faire 3 références à 1 liste.
Vous vous demandez *
peut- être pourquoi vous ne pouvez pas créer des objets indépendants comme le fait la compréhension de la liste. En effet, l'opérateur de multiplication *
opère sur des objets, sans voir d'expressions. Lorsque vous utilisez *
pour multiplier [[1] * 4]
par 3, *
seule la liste à 1 élément est [[1] * 4]
évaluée, pas le [[1] * 4
texte de l' expression. *
n'a aucune idée de comment faire des copies de cet élément, aucune idée de la façon de réévaluer [[1] * 4]
, et aucune idée que vous voulez même des copies, et en général, il pourrait même ne pas y avoir de moyen de copier l'élément.
La seule option *
est de faire de nouvelles références à la sous-liste existante au lieu d'essayer de faire de nouvelles sous-listes. Tout le reste serait incohérent ou nécessiterait une refonte majeure des décisions fondamentales de conception du langage.
En revanche, une compréhension de liste réévalue l'expression de l'élément à chaque itération. [[1] * 4 for n in range(3)]
réévalue à [1] * 4
chaque fois pour la même raison [x**2 for x in range(3)]
réévalue à x**2
chaque fois. Chaque évaluation de [1] * 4
génère une nouvelle liste, donc la compréhension de la liste fait ce que vous vouliez.
Soit dit en passant, [1] * 4
ne copie pas non plus les éléments de [1]
, mais cela n'a pas d'importance, car les entiers sont immuables. Vous ne pouvez pas faire quelque chose comme 1.value = 2
et transformer un 1 en 2.
[x]*3
stocker 3 références comme[x, x, x]
c'est juste quandx
est mutable. Cela ne fonctionne pas pour, par exemplea=[4]*3
, où aprèsa[0]=5
,a=[5,4,4].