Когда вы пишете, [x]*3
вы получаете, по сути, список [x, x, x]
. То есть список с 3 ссылками на одно и то же x
. Когда вы затем изменяете этот сингл, x
он виден через все три ссылки на него:
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]]
Чтобы это исправить, вам нужно убедиться, что вы создаете новый список в каждой позиции. Один из способов сделать это
[[1]*4 for _ in range(3)]
который будет переоценивать [1]*4
каждый раз вместо того, чтобы оценивать его один раз и делать 3 ссылки на 1 список.
Вы можете задаться вопросом, почему *
нельзя создавать независимые объекты так, как это делает понимание списка. Это потому, что оператор умножения *
работает с объектами, не видя выражений. Когда вы используете *
умножение [[1] * 4]
на 3, *
видит только 1-элементный список [[1] * 4]
, а не [[1] * 4
выражение выражения. *
не знает, как сделать копии этого элемента, не знает, как переоценить [[1] * 4]
, и даже не подозревает, что вам даже нужны копии, и вообще, может даже не быть способа скопировать элемент.
Единственный вариант *
- создавать новые ссылки на существующий подсписок, а не пытаться создавать новые подсписки. Все остальное будет противоречивым или потребует серьезного изменения основных решений по языку.
Напротив, понимание списка переоценивает выражение элемента на каждой итерации. [[1] * 4 for n in range(3)]
переоценка [1] * 4
каждый раз по той же причине [x**2 for x in range(3)]
переоценка x**2
каждый раз. Каждая оценка [1] * 4
генерирует новый список, поэтому понимание списка делает то, что вы хотели.
Кстати, [1] * 4
также не копирует элементы [1]
, но это не имеет значения, поскольку целые числа неизменны. Вы не можете сделать что-то вроде 1.value = 2
и превратить 1 в 2.
[x]*3
Храните 3 ссылки, как[x, x, x]
только правильно, когдаx
изменчиво. Это не работает, напримерa=[4]*3
, где послеa[0]=5
,a=[5,4,4].