Коли ви пишете, [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].