Kiedy piszesz [x]*3, dostajesz w zasadzie listę [x, x, x]. To znaczy lista z 3 odniesieniami do tego samego x. Kiedy następnie zmodyfikujesz ten singiel, xbędzie on widoczny poprzez wszystkie trzy odniesienia do niego:
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]]
Aby to naprawić, musisz utworzyć nową listę w każdej pozycji. Jednym ze sposobów na to jest
[[1]*4 for _ in range(3)]
który za [1]*4każdym razem będzie ponownie oceniać, zamiast oceniać go raz i czyniąc 3 odniesienia do 1 listy.
Możesz się zastanawiać, dlaczego *nie można tworzyć niezależnych obiektów w taki sposób, jak robi to lista. Jest tak, ponieważ operator mnożenia *działa na obiektach, nie widząc wyrażeń. Kiedy używasz *do pomnożenia [[1] * 4]przez 3, *widzi tylko listę 1-elementową [[1] * 4], a nie [[1] * 4tekst wyrażenia. *nie ma pojęcia, jak wykonać kopię tego elementu, nie ma pojęcia, jak dokonać ponownej oceny [[1] * 4], i nie ma pojęcia, że chcesz kopii, a ogólnie rzecz biorąc, może nie być nawet sposobu na skopiowanie elementu.
Jedyną opcją *jest tworzenie nowych odniesień do istniejącej listy podrzędnej zamiast prób tworzenia nowych list podrzędnych. Wszystko inne byłoby niespójne lub wymagałoby poważnego przeprojektowania podstawowych decyzji dotyczących projektowania języka.
W przeciwieństwie do tego, zrozumienie listy ponownie ocenia wyrażenie elementu przy każdej iteracji. [[1] * 4 for n in range(3)]ponownej waloryzacji [1] * 4za każdym razem z tego samego powodu [x**2 for x in range(3)]ponownej waloryzacji x**2za każdym razem. Każda ocena [1] * 4generuje nową listę, więc zrozumienie listy robi to, co chciałeś.
Nawiasem mówiąc, [1] * 4również nie kopiuje elementów [1], ale to nie ma znaczenia, ponieważ liczby całkowite są niezmienne. Nie możesz zrobić czegoś takiego 1.value = 2i zmienić 1 w 2.
[x]*3przechowuj 3 odnośniki, tak jak[x, x, x]jest właściwe tylko wtedy, gdyxmożna je modyfikować. To dzieło nie podlega na przykłada=[4]*3, gdzie poa[0]=5,a=[5,4,4].