Когда вы пишете, [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].
[4]*3
по существу эквивалентноx = 4; [x, x, x]
. Правда, это никогда не вызовет никаких проблем, так как4
является неизменным. Кроме того, ваш другой пример не совсем другой случай.a = [x]*3; a[0] = 5
не вызовет проблем, даже еслиx
он изменчив, так как вы не модифицируетеx
, а только модифицируетеa
. Я бы не назвал свой ответ вводящим в заблуждение или неправильным - вы просто не можете выстрелить себе в ногу, если имеете дело с неизменными объектами.x = 1000; lst = [x]*2; lst[0] is lst[1]
->True
. Python вообще не различает изменяемые и неизменяемые объекты.Live Python Tutor Визуализируйте
источник
x
ссылается. Если выx = object()
matrix = [[x] * 2]
matrix[0][0] is matrix[0][1]
list
), поэтому, если arow = [x] * 2
чем a,matrix = [row] * 2
где обе строки являются точно одним и тем же объектом, и теперь изменения одной строкиmatrix[0][0] = y
неожиданно отражаются на другой(matrix[0][0] is matrix[1][0]) == True
На самом деле, это именно то, что вы ожидаете. Давайте разложим то, что здесь происходит:
Ты пишешь
Это эквивалентно:
Это означает
lst
, что список состоит из трех элементов, на которые все указываютlst1
. Это означает, что две следующие строки эквивалентны:Как
lst[0]
ничего кромеlst1
.Чтобы получить желаемое поведение, вы можете использовать понимание списка:
В этом случае выражение переоценивается для каждого n, что приводит к другому списку.
источник
id(lst[0][0])
и /id(lst[1][0])
или дажеid(lst[0])
иid(lst[1])
или даже:
Создает список, который ссылается на внутренний
[1,1,1,1]
3 раза, а не на три копии внутреннего списка, поэтому каждый раз, когда вы изменяете список (в любой позиции), вы увидите изменение три раза.Это так же, как этот пример:
где это, вероятно, немного менее удивительно.
источник
Наряду с принятым ответом, который правильно объяснил проблему, в вашем понимании списка, если вы используете python-2.x, используйте
xrange()
возвращающий генератор, который более эффективен (range()
в python 3 выполняет ту же работу)_
вместо переменной throwawayn
:Кроме того, как гораздо более Pythonic способ вы можете использовать
itertools.repeat()
для создания объекта итератора из повторяющихся элементов:PS Использование NumPy, если вы хотите создать массив из единиц или нулей , которые можно использовать
np.ones
иnp.zeros
и / или для другого использования номераnp.repeat()
:источник
Контейнеры Python содержат ссылки на другие объекты. Смотрите этот пример:
В этом
b
списке содержится один элемент, который является ссылкой на списокa
. Списокa
изменчив.Умножение списка на целое число эквивалентно добавлению списка к себе несколько раз (см. Общие операции с последовательностями ). Итак, продолжаем с примером:
Мы можем видеть, что список
c
теперь содержит две ссылки на список,a
который эквивалентенc = b * 2
.Python FAQ также содержит объяснение этого поведения: как мне создать многомерный список?
источник
myList = [[1]*4] * 3
создает один объект списка[1,1,1,1]
в памяти и копирует его ссылку 3 раза. Это эквивалентноobj = [1,1,1,1]; myList = [obj]*3
. Любое изменениеobj
будет отражено в трех местах, где бы они ниobj
упоминались в списке. Правильное утверждение будет:или
Здесь важно отметить, что
*
оператор в основном используется для создания списка литералов . Хотя1
является неизменным,obj =[1]*4
все равно будет создавать список1
повторяется 4 раза в форме[1,1,1,1]
. Но если делается какая-либо ссылка на неизменный объект, объект перезаписывается новым.Это означает, что если мы это сделаем
obj[1]=42
, тоobj
станет[1,42,1,1]
не так,как некоторые могут предположить. Это также можно проверить:[42,42,42,42]
источник
obj[2] = 42
заменяет ссылку на индекс2
, в отличие от изменения объекта, на который ссылается этот индекс, что и естьmyList[2][0] = ...
(myList[2]
является списком, и задание изменяет ссылку на индекс 0 в списке). Конечно, целые числа не изменяемые, но множество типов объектов являются . И обратите внимание, что[....]
нотация отображения списка также является формой буквального синтаксиса! Не путайте составные (например, списки) и скалярные объекты (например, целые числа) с изменяемыми и неизменяемыми объектами.Проще говоря, это происходит потому, что в python все работает по ссылке , поэтому, когда вы создаете список списков таким образом, вы в основном сталкиваетесь с такими проблемами.
Чтобы решить вашу проблему, вы можете сделать одно из них: 1. Используйте документацию для numpy array для numpy.empty 2. Добавьте список по мере его появления. 3. Вы также можете использовать словарь, если хотите
источник
Давайте перепишем ваш код следующим образом:
Затем, выполнив следующий код, сделайте все более понятным. То, что делает код, - это, в основном, печать
id
полученных объектов, которыеи поможет нам идентифицировать их и проанализировать, что происходит:
И вы получите следующий вывод:
Итак, давайте пойдем пошагово. У вас есть
x
что1
, и один элемент списка,y
содержащийx
. Ваш первый шаг заключается в том,y * 4
что вы получите новый списокz
, то есть, в основном[x, x, x, x]
, то есть создаст новый список, который будет иметь 4 элемента, которые являются ссылками на исходныйx
объект. Чистый шаг очень похож. Вы в основном делаетеz * 3
, что есть[[x, x, x, x]] * 3
и возвращается[[x, x, x, x], [x, x, x, x], [x, x, x, x]]
, по той же причине, что и для первого шага.источник
Я думаю, что все объясняют, что происходит. Я предлагаю один способ решить это:
myList = [[1 for i in range(4)] for j in range(3)]
print myList
И тогда у вас есть:
источник
Пытаясь объяснить это более наглядно,
Операция 1:
Операция 2:
Заметил, почему изменение первого элемента первого списка не изменило второй элемент каждого списка? Это потому, что на
[0] * 2
самом деле это список из двух чисел, и ссылка на 0 не может быть изменена.Если вы хотите создать копии клонов, попробуйте операцию 3:
еще один интересный способ создания копий клонов, операция 4:
источник
@spelchekr из списка умножения Python: [[...]] * 3 создает 3 списка, которые отражают друг друга при модификации, и у меня возник тот же вопрос: «Почему только внешний * 3 создает больше ссылок, а внутренний - нет? ? Почему не все 1? "
Вот мое объяснение после попытки кода выше:
*3
также создает ссылки, но его ссылки являются неизменными, что-то вроде того[&0, &0, &0]
, тогда, когда изменитьli[0]
, вы не можете изменить любую основную ссылку const int0
, поэтому вы можете просто изменить адрес ссылки на новый&1
;ma=[&li, &li, &li]
иli
является изменяемым, поэтому, когда вы вызываетеma[0][0]=1
, ma [0] [0] равно&li[0]
, так что все&li
экземпляры будут менять свой 1-й адрес на&1
.источник
Используя встроенную функцию списка, вы можете сделать это
источник
a.insert(0,[5,1,1,1])