Почему обновление словаря "мелкой" копии не обновляет "оригинальный" словарь?
При чтении документации для dict.copy() там говорится, что создается мелкая копия словаря. То же самое касается книги, на которую я ссылаюсь (справочник Бизли по Python), в которой говорится:
Метод m.copy() создает мелкую копию элементов, содержащихся в объекте сопоставления, и помещает их в новый объект сопоставления.
Учтите это:
>>> original = dict(a=1, b=2) >>> new = original.copy() >>> new.update({'c': 3}) >>> original {'a': 1, 'b': 2} >>> new {'a': 1, 'c': 3, 'b': 2}
Итак, я предположил, что это обновит значение original (и добавит 'c': 3) также, поскольку я делал мелкую копию. Нравится, если вы делаете это для списка:
>>> original = [1, 2, 3] >>> new = original >>> new.append(4) >>> new, original ([1, 2, 3, 4], [1, 2, 3, 4])
Это работает так, как ожидалось.
Поскольку оба являются мелкими копиями, почему dict.copy() работает не так, как я ожидаю? Или мое понимание мелкого и глубокого копирования ошибочно?
Переведено автоматически
Ответ 1
Под "мелким копированием" подразумевается, что содержимое словаря не копируется по значению, а просто создается новая ссылка.
>>> a = {1: [1,2,3]} >>> b = a.copy() >>> a, b ({1: [1, 2, 3]}, {1: [1, 2, 3]}) >>> a[1].append(4) >>> a, b ({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
Напротив, глубокая копия скопирует все содержимое по значению.
>>> import copy >>> c = copy.deepcopy(a) >>> a, c ({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]}) >>> a[1].append(5) >>> a, c ({1: [1, 2, 3, 4, 5]}, {1: [1, 2, 3, 4]})
Итак:
b = a: Назначение ссылок, Make a и b указывают на один и тот же объект.
b = a.copy(): Мелкое копирование, a и b станут двумя изолированными объектами, но их содержимое по-прежнему будет иметь одну и ту же ссылку
b = copy.deepcopy(a): Глубокое копирование, a и b структура и содержимое становятся полностью изолированными.
Ответ 2
Возьмем этот пример:
original = dict(a=1, b=2, c=dict(d=4, e=5)) new = original.copy()
Теперь давайте изменим значение на "мелком" (первом) уровне:
new['a'] = 10 # new = {'a': 10, 'b': 2, 'c': {'d': 4, 'e': 5}} # original = {'a': 1, 'b': 2, 'c': {'d': 4, 'e': 5}} # no change in original, since ['a'] is an immutable integer
Теперь давайте изменим значение на один уровень глубже:
new['c']['d'] = 40 # new = {'a': 10, 'b': 2, 'c': {'d': 40, 'e': 5}} # original = {'a': 1, 'b': 2, 'c': {'d': 40, 'e': 5}} # new['c'] points to the same original['d'] mutable dictionary, so it will be changed
Ответ 3
Дело не в глубокой копии или мелком копировании, ничто из того, что вы делаете, не является глубокой копией.
Здесь:
>>> new = original
вы создаете новую ссылку на список / dict, на который ссылается original.
находясь здесь:
>>> new = original.copy() >>> # or >>> new = list(original) # dict(original)
вы создаете новый список / dict, который заполняется копией ссылок на объекты, содержащиеся в исходном контейнере.
Ответ 4
Добавление к ответу kennytm. Когда вы выполняете мелкую копию parent.copy() создается новый словарь с теми же ключами, но значения не копируются, на них ссылаются.Если вы добавите новое значение в parent_copy, это не повлияет на parent, потому что parent_copy - это новый словарь, а не ссылка.
Значение хэша (id) для parent[1], parent_copy[1] идентичны, что подразумевает [1,2,3] для parent[1] и parent_copy[1] хранятся с идентификатором 140690938288400.
Но хэш parent и parent_copy разные, что подразумевает, что это разные словари, а parent_copy - это новый словарь, значения которого ссылаются на значения parent