Как сделать полностью неразделенную копию сложного списка? (Глубокая копия не достаточно)

python list copy

10350 просмотра

5 ответа

Посмотрите на этот код Python:

a = [1, 2, 3]
b = [4, 5, 6]
c = [[a, b], [b, a]] # [[[1, 2, 3], [4, 5, 6]], [[4, 5, 6], [1, 2, 3]]]
c[0][0].append(99)   # [[[1, 2, 3, 99], [4, 5, 6]], [[4, 5, 6], [1, 2, 3, 99]]]

Обратите внимание, как модификация одного элемента cмодифицирует это везде. То есть, если 99добавлено c[0][0], оно также добавлено c[1][1]. Я предполагаю, что это потому, что Python ловко ссылается на один и тот же объект для c[0][0]и c[1][1]. (То есть их id () одинаков.)

Вопрос: Есть ли что-то, что можно сделать, чтобы cего элементы списка можно было безопасно локально изменить? Выше приведен только пример, моя настоящая проблема имеет список гораздо более сложный, но с аналогичной проблемой.

(Извините за плохо сформулированный вопрос выше. Гуру Python, пожалуйста, не стесняйтесь изменять вопрос или теги, чтобы лучше выразить этот запрос.)

Автор: Ashwin Nanjappa Источник Размещён: 13.11.2019 11:44

Ответы (5)


8 плюса

Решение

Чтобы преобразовать существующий список списков в тот, где ничего не передано, вы можете рекурсивно скопировать список.

deepcopyэтого будет недостаточно, поскольку он будет копировать структуру как есть, сохраняя внутренние ссылки в качестве ссылок, а не копий.

def unshared_copy(inList):
    if isinstance(inList, list):
        return list( map(unshared_copy, inList) )
    return inList

alist = unshared_copy(your_function_returning_lists())

Обратите внимание, что предполагается, что данные возвращаются в виде списка списков (произвольно вложенных). Если контейнеры относятся к разным типам (например, массивы numpy, dict или пользовательские классы), вам может потребоваться изменить это.

Автор: Brian Размещён: 21.10.2009 03:49

8 плюса

Когда вам нужна копия, вы явно делаете копию - загадочная [:]форма «нарезать все» идиоматична, но мой фаворит - гораздо более читаемый подход явного вызова list.

Если cон построен неправильно (со ссылками вместо мелких копий на списки, которые вы хотите иметь возможность изменять независимо), лучше всего было бы исправить способ, которым он построен (зачем создавать его неправильно, а затем пытаться исправить это ?!) , но если это не под вашим контролем, можно отменить повреждение - просто включите c(рекурсивно, если необходимо) с индексом, переназначая соответствующие списки для их копий. Например, если вы точно знаете, что cструктура двухуровневая, как вы указали, вы можете сохранить себя без рекурсии:

def fixthewronglymadelist(c):
  for topsublist in c:
    for i, L in enumerate(topsublist):
      topsublist[i] = list(L)

Несмотря на то, что предлагают другие ответы, copy.deepcopyбыло бы трудно склониться к этой особой цели, если бы все, что вам дали, было сделано неправильно c: выполнение просто copy.deepcopy(c)аккуратно скопировало бы любую топологию c, включая множественные ссылки на одни и те же подсписки! :-)

Автор: Alex Martelli Размещён: 21.10.2009 02:47

5 плюса

В зависимости от вашей ситуации, вы можете работать с глубокой копией этого списка.

Автор: Pesto Размещён: 21.10.2009 02:42

5 плюса

Используйте [:]:

>>> a = [1, 2]
>>> b = a[:]
>>> b.append(9)
>>> a
[1, 2]

Альтернативно, используйте copyилиdeepcopy :

>>> import copy
>>> a = [1, 2]
>>> b = copy.copy(a)
>>> b.append(9)
>>> a
[1, 2]

copyработает с объектами, отличными от списков. Для списков это имеет тот же эффект, что и a[:]. deepcopyпытается рекурсивно копировать вложенные элементы, и, таким образом, это более «тщательная» операция, чем copy.

Автор: Stephan202 Размещён: 21.10.2009 02:41

1 плюс

Чтобы увидеть предложение Стефана на работе, сравните два результата ниже:

a = [1, 2, 3]
b = [4, 5, 6]
c = [[a, b], [b, a]]
c[0][0].append(99)
print c
print "-------------------"
a = [1, 2, 3]
b = [4, 5, 6]
c = [[a[:], b[:]], [b[:], a[:]]]
c[0][0].append(99)
print c

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

[[[1, 2, 3, 99], [4, 5, 6]], [[4, 5, 6], [1, 2, 3, 99]]]
-------------------
[[[1, 2, 3, 99], [4, 5, 6]], [[4, 5, 6], [1, 2, 3]]]
Автор: Michael Dillon Размещён: 21.10.2009 02:47
Вопросы из категории :
32x32