У меня возникла проблема с этим в течение пары месяцев, и эта небольшая строка исправила все. Хотелось бы, чтобы я прочитал это раньше!
sudo dpkg -i --force-overwrite /var/cache/apt/archives/libqtcore4_4%3a4.8.7+dfsg-5ubuntu2_amd64.deb
Попытка объяснить это более описательно,
Операция 1:
x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]
x[0][0] = 1
print(x) # [[1, 0], [0, 0]]
Операция 2:
y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]
y[0][0] = 1
print(y) # [[1, 0], [1, 0]]
Заметил, почему не изменяет первый элемент первого списка не изменил второй элемент каждого списка? Это потому, что [0] * 2 действительно является списком из двух чисел, а ссылка на 0 не может быть изменена.
Если вы хотите создать копии клонов, попробуйте выполнить операцию 3:
import copy
y = [0] * 2
print(y) # [0, 0]
y = [y, copy.deepcopy(y)]
print(y) # [[0, 0], [0, 0]]
y[0][0] = 1
print(y) # [[1, 0], [0, 0]]
] еще один интересный способ создания копий клонов, операция 4:
import copy
y = [0] * 2
print(y) # [0, 0]
y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]
y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]
Используя встроенную функцию списка, вы можете сделать это
a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list
a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number
a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting
a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list
Я думаю, все объясняют, что происходит. Я предлагаю один из способов его решения:
myList = [[1 for i in range(4)] for j in range(3)]
myList[0][0] = 5
print myList
И тогда у вас есть:
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
Давайте перепишем ваш код следующим образом:
x = 1
y = [x]
z = y * 4
myList = [z] * 3
После этого запустите следующий код, чтобы сделать все более понятным. Что делает код, в основном печатает id s полученных объектов, которые
возвращают «идентификатор» объектаи помогут нам идентифицировать их и проанализировать, что происходит :
print("myList:")
for i, subList in enumerate(myList):
print("\t[{}]: {}".format(i, id(subList)))
for j, elem in enumerate(subList):
print("\t\t[{}]: {}".format(j, id(elem)))
И вы получите следующий результат:
x: 1
y: [1]
z: [1, 1, 1, 1]
myList:
[0]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[1]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
[2]: 4300763792
[0]: 4298171528
[1]: 4298171528
[2]: 4298171528
[3]: 4298171528
Итак, теперь давайте шаг за шагом. У вас есть 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]] по той же причине, что и для первого шага.
size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for i in range(size)]
Live Python Tutor Визуализировать
Собственно, подумайте об этом в другом случае. Предположим, что если ваш список таков:
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
, и если вы напишете myList[0][0] = 5, будет выводиться:
>>>
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>>
Как и ожидалось. Но так как вы определяете свою переменную списка следующим образом:
[[1] * 4] * 3
Python обработает ваши коды по этому шаблону. Поэтому, если вы напишете myList[0][0] и ваш список, как указано выше, Python обработает его, как [1]*3. Вот почему все списки первых элементов изменены.
myList = [[1]*4] * 3 создает один объект списка [1,1,1,1] в памяти и копирует его ссылку 3 раза. Это эквивалентно obj = [1,1,1,1]; myList = [obj]*3. Любая модификация obj будет отражена в трех местах, где obj упоминается в списке. Правильный оператор:
myList = [[1]*4 for _ in range(3)]
или
myList = [[1 for __ in range(4)] for _ in range(3)]
Важно отметить, что оператор * в основном используется для создания списка литералов. Поскольку 1 является литералом, значит, obj =[1]*4 создаст [1,1,1,1], где каждый 1 будет атомарным, а не ссылкой 1, повторяемым 4 раза. Это означает, что если мы obj[2]=42, то obj станет [1,1,42,1] не [42,42,42,42], как могут предположить некоторые.
[[1] * 4] * 3
или даже:
[[1, 1, 1, 1]] * 3
Создает список, который ссылается на внутренний [1,1,1,1] 3 раза - не три копии внутреннего списка, поэтому в любое время, когда вы изменяете список (в любом позиция), вы увидите изменение три раза.
Это то же самое, что и в этом примере:
>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]
, где это, вероятно, немного менее удивительно.
Наряду с принятым ответом, который правильно объяснил проблему, в понимании вашего списка, если вы используете python-2.x, используйте xrange(), который возвращает более эффективный генератор (range() в python 3 выполняет ту же работу ) _ вместо переменной throwaway n:
[[1]*4 for _ in xrange(3)] # and in python3 [[1]*4 for _ in range(3)]
Кроме того, в качестве гораздо более питонического способа вы можете использовать itertools.repeat() для создания объекта итератора повторяющихся элементов:
>>> a=list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0]=5
>>> a
[5, 1, 1, 1]
PS Используя numpy, если вы хотите создать только массив единиц или нулей, вы можете использовать np.ones и np.zeros и / или для использования других чисел np.repeat():
In [1]: import numpy as np
In [2]:
In [2]: np.ones(4)
Out[2]: array([ 1., 1., 1., 1.])
In [3]: np.ones((4, 2))
Out[3]:
array([[ 1., 1.],
[ 1., 1.],
[ 1., 1.],
[ 1., 1.]])
In [4]: np.zeros((4, 2))
Out[4]:
array([[ 0., 0.],
[ 0., 0.],
[ 0., 0.],
[ 0., 0.]])
In [5]: np.repeat([7], 10)
Out[5]: array([7, 7, 7, 7, 7, 7, 7, 7, 7, 7])
Простыми словами это происходит потому, что в python все работает по ссылке, поэтому, когда вы создаете список списков таким образом, вы в основном получаете такие проблемы.
Чтобы решить вашу проблему, вы можете сделать либо один из них: 1. Используйте документацию массива numpy для numpy.empty 2. Добавляйте список, когда вы попадаете в список. 3. Вы также можете использовать словарь, если вы хотите
На самом деле это именно то, чего вы ожидаете. Давайте разложим, что здесь происходит:
Вы пишете
lst = [[1] * 4] * 3
Это эквивалентно:
lst1 = [1]*4
lst = [lst1]*3
Это означает, что lst - это список с 3 элемента, указывающие на lst1. Это означает, что две следующие строки эквивалентны:
lst[0][0] = 5
lst1[0] = 5
Поскольку lst[0] - это только lst1.
Чтобы получить желаемое поведение, вы можете использовать понимание списка: [ ! d5]
lst = [ [1]*4 for n in xrange(3) ]
В этом случае выражение переоценивается для каждого n, что приводит к другому списку.
Контейнеры Python содержат ссылки на другие объекты. См. Этот пример:
>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]
В этом b есть список, содержащий один элемент, который является ссылкой на список a. Список a изменен.
Умножение списка на целое эквивалентно добавлению списка к себе несколько раз (см. Операции общей последовательности). Итак, продолжаем с примера:
>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]
Мы видим, что список c теперь содержит две ссылки на список a, который эквивалентен c = b * 2.
Python Часто задаваемые вопросы также содержат объяснение этого поведения: операции общей последовательности