Python: список подписки с добавлением [dубликат]

У меня возникла проблема с этим в течение пары месяцев, и эта небольшая строка исправила все. Хотелось бы, чтобы я прочитал это раньше!

sudo dpkg -i --force-overwrite  /var/cache/apt/archives/libqtcore4_4%3a4.8.7+dfsg-5ubuntu2_amd64.deb
413
задан 22 March 2017 в 20:14

12 ответов

Попытка объяснить это более описательно,

Операция 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]]
1
ответ дан 15 August 2018 в 16:37

Используя встроенную функцию списка, вы можете сделать это

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
1
ответ дан 15 August 2018 в 16:37
  • 1
    Это работает, но не объясняет, что происходит. – Luigi Ballabio 15 July 2016 в 17:06

Я думаю, все объясняют, что происходит. Я предлагаю один из способов его решения:

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]]
1
ответ дан 15 August 2018 в 16:37

Давайте перепишем ваш код следующим образом:

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]] по той же причине, что и для первого шага.

1
ответ дан 15 August 2018 в 16:37
size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for i in range(size)]

Live Python Tutor Визуализировать

88
ответ дан 15 August 2018 в 16:37
  • 1
    Я поставил ваш образ в линию. Для справок в будущем вам действительно нужно объяснить, к чему вы привязываетесь. – Blckknght 27 August 2013 в 05:42
  • 2
    Отличный инструмент! Спасибо за ссылку – Dennis 27 February 2016 в 19:43
  • 3
    Итак, почему, если мы пишем matrix = [[x] * 2], не делаем 2 элемента для одного и того же объекта, как в примере, который вы описываете, это похоже на ту же концепцию, чего я не вижу? – Ahmed Mohamed 1 July 2017 в 20:55
  • 4
    @AhmedMohamed Действительно, он делает список с двумя элементами того же самого объекта, к которому относится x. Если вы сделаете глобально уникальный объект с x = object(), а затем сделаете matrix = [[x] * 2], это произойдет как истина: matrix[0][0] is matrix[0][1] – nadrimajstor 2 July 2017 в 16:13

Собственно, подумайте об этом в другом случае. Предположим, что если ваш список таков:

[[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. Вот почему все списки первых элементов изменены.

-2
ответ дан 15 August 2018 в 16:37

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], как могут предположить некоторые.

2
ответ дан 15 August 2018 в 16:37
[[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]]

, где это, вероятно, немного менее удивительно.

26
ответ дан 15 August 2018 в 16:37

Наряду с принятым ответом, который правильно объяснил проблему, в понимании вашего списка, если вы используете 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])
5
ответ дан 15 August 2018 в 16:37

Простыми словами это происходит потому, что в python все работает по ссылке, поэтому, когда вы создаете список списков таким образом, вы в основном получаете такие проблемы.

Чтобы решить вашу проблему, вы можете сделать либо один из них: 1. Используйте документацию массива numpy для numpy.empty 2. Добавляйте список, когда вы попадаете в список. 3. Вы также можете использовать словарь, если вы хотите

4
ответ дан 15 August 2018 в 16:37

На самом деле это именно то, чего вы ожидаете. Давайте разложим, что здесь происходит:

Вы пишете

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, что приводит к другому списку.

37
ответ дан 15 August 2018 в 16:37
  • 1
    Это действительно понятно для новичка, подобного мне. Спасибо! – Petite Etincelle 29 April 2016 в 11:18
  • 2
    Просто небольшое дополнение к приятному ответу здесь: очевидно, что вы имеете дело с одним и тем же объектом, если вы делаете id(lst[0][0]) и id(lst[1][0]) или даже id(lst[0]) и id(lst[1]) – Sergiy Kolodyazhnyy 17 May 2017 в 10:08

Контейнеры 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 Часто задаваемые вопросы также содержат объяснение этого поведения: операции общей последовательности

1
ответ дан 15 August 2018 в 16:37

Другие вопросы по тегам:

Похожие вопросы: