Список внезапно изменился, хотя я его не меняю

У меня довольно сложный код. Есть три списка. Вкратце - нужно сравнить список1 и список сравнения, и если найдено какое-то конкретное совпадение, мы добавляем значения из списка1 в список2. Весь код следует

list1 = [['item1', ['item2'], '0', '0'], ['item3', ['item4'], '107', '2'], ['item4.5', ['item5', 'item4.5 aaa'], '120', '2'], ['item6', ['item6 item6 aaa'], '127', '1'], ['item7', ['item7 item7 aaa'], '129', '1']]
comparsion_list = [['item1', ['item2'], 'unknown'], ['item3', ['item4'], 'unknown'], ['item4.5', ['item5', 'item4.5 aaa'], 'unknown'], ['item6', ['item6 item6 aaa'], 'unknown']]
list2 = [['category', ['keywords'], ['long-names'], 'amount', 'amount2'],['empty', ['empty'], ['empty'], 'empty', 'empty']]

for a in range(len(comparsion_list)): #we go trough comparsion_list -start number is 1, end is category len
    for i in range(len(list1)): #and compare them with each item of list1

        if list1[i][1][0] in comparsion_list[a][1] and comparsion_list[a][2] not in [x[0] for x in list2]:
            list2.append([comparsion_list[a][2]]) #append item to list2 as list (to create row)
            list2[-1].append([list1[i][0]])
            list2[-1].append(list1[i][1])
            print("list1 before elif is: "+str(list1[0]))  #just for testing - everything still ok

        elif list1[i][1][0] in comparsion_list[a][1] and comparsion_list[a][2] == list2[-1][0]:
            print("list1 after elif is: "+str(list1[0])) #just for testing - not ok!
            list2[-1][2].extend(list1[i][1])

Но вывод следующий:

list1 before elif is: ['item1', ['item2'], '0', '0']
list1 after elif is: ['item1', ['item2'], '0', '0']
list1 after elif is: ['item1', ['item2', 'item4'], '0', '0']
list1 after elif is: ['item1', ['item2', 'item4', 'item5', 'item4.5 aaa'], '0', '0']

Как видите, list1 изменен, но я не менял все это в коде! там даже нет ссылок, так как это всегда глубокая копия, а deep_of_list1 остается неизменным. Я думал, что ожидаемый результат должен выглядеть так:

list1 before elif is: ['item1', ['item2'], '0', '0']
list1 after elif is: ['item1', ['item2'], '0', '0']
list1 after elif is: ['item1', ['item2'], '0', '0']
list1 after elif is: ['item1', ['item2'], '0', '0']

Но когда я удаляю эту строку (из оператора elif):

    list2[-1][2].extend(list1[i][1])

Тогда выход в порядке (второй). Как такое возможно? Что мне не хватает?

Пожалуйста, сделайте минимальный воспроизводимый пример и удалите свой вопрос из кода, который не является необходимым для вопроса.

timgeb 11.04.2018 12:47

Ваш фрагмент кода настолько запутан, что я отказался от попыток понять его - на самом деле, это шум строки. И такие вещи, как deep_of_list1 = deepcopy(list1); list1 = deepcopy(deep_of_list1), действительно не помогают.

bruno desthuilliers 11.04.2018 13:05

Как вы думаете, почему ваши дипкопии должны защищать вас от этого? Вы явно делаете различные добавления изменяемых объектов и т. д., А затем изменяете их ...

juanpa.arrivillaga 11.04.2018 13:10

Ну, у меня вопрос, как это возможно, что список1 изменился, если в него не было внесено никаких изменений (нет добавлений / расширений, это не ссылка), и когда я удаляю последнюю строку, где я добавляю в список2, это нормально. ..

Andreas Bekkelund 11.04.2018 13:18

@AndreasBekkelund, что значит "это не ссылка"? Вы явно .append ссылаетесь на элементы внутри list1 на list2, затем вы мутируете элементы в list2, которые могут быть теми же элементами в list1 ... Вы продолжаете повторять «ссылок нет», но это явно неверно, так что либо вы неправильно понимаете, что глубокая копия делает или есть какое-то недопонимание

juanpa.arrivillaga 11.04.2018 20:52
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
5
67
1

Ответы 1

Вы добавляете ссылки на элементы list1 в list2. Один из этих элементов сам является изменяемым (list). Ваша проблема решена, если вы принудительно создаете новый объект памяти, явно скопировав список.

list2[-1].append(list1[i][1].copy()) #in the 'if' part of the code.

Кроме того, я бы, наверное, реорганизовал всего монстра ..

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