Вопрос-Ответ

How to copy a dictionary and only edit the copy

Как скопировать словарь и редактировать только копию

Я установил dict2 = dict1. Когда я редактирую dict2, оригинал dict1 также меняется. Почему?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
Переведено автоматически
Ответ 1

Python никогда неявно копирует объекты. Когда вы устанавливаете dict2 = dict1, вы заставляете их ссылаться на один и тот же точный объект dict, поэтому, когда вы изменяете его, все ссылки на него продолжают ссылаться на объект в его текущем состоянии.

Если вы хотите скопировать dict (что случается редко), вы должны сделать это явно с помощью

dict2 = dict(dict1)

или

dict2 = dict1.copy()
Ответ 2

Когда вы присваиваете dict2 = dict1, вы не создаете копию dict1, это приводит к тому, что dict2 это просто другое имя для dict1.

Чтобы скопировать изменяемые типы, такие как словари, используйте copy / deepcopy из copy модуля.

import copy

dict2 = copy.deepcopy(dict1)
Ответ 3

Хотя dict.copy() and dict(dict1) генерирует копию, это всего лишь неглубокие копии. Если вам нужна глубокая копия, copy.deepcopy(dict1) требуется. Пример:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = source.copy()
>>> copy2 = dict(source)
>>> import copy
>>> copy3 = copy.deepcopy(source)
>>> source['a'] = 10 # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40 # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3 # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

Что касается неглубоких и глубоких копий, из Python copy module docs:


Разница между мелким и глубоким копированием актуальна только для составных объектов (объектов, которые содержат другие объекты, такие как списки или экземпляры классов):




  • Поверхностная копия создает новый составной объект, а затем (насколько это возможно) вставляет в него ссылки на объекты, найденные в оригинале.

  • Глубокая копия создает новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале.


Ответ 4

Подробно и простой способ запоминания:

Всякий раз, когда вы это делаете dict2 = dict1, dict2 ссылается на dict1. Оба dict1 и dict2 указывают на одно и то же место в памяти. Это обычный случай при работе с изменяемыми объектами в Python. При работе с изменяемыми объектами в Python вы должны быть осторожны, так как их сложно отлаживать.

Вместо использования dict2 = dict1 вам следует использовать copy(мелкое копирование) или deepcopy метод из модуля копирования python для отделения dict2 от dict1.

Правильный способ сделать это:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?"
>>> dict2
{'key1': 'value1', 'key2': 'WHY?'}
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>> id(dict1)
140641178056312
>>> id(dict2)
140641176198960
>>>

Как вы можете видеть, id обоих dict1 и dict2 различны, что означает, что они указывают на разные местоположения в памяти.

Это решение работает для словарей с неизменяемыми значениями, но это неправильное решение для словарей с изменяемыми значениями.

Остерегайтесь изменяемых значений в вашем словаре:

>>> import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': False}}
>>> id(dict1)
140641197660704
>>> id(dict2)
140641196407832
>>> id(dict1["key2"])
140641176198960
>>> id(dict2["key2"])
140641176198960

Вы можете видеть, что, хотя мы применили copy для dict1 , значение mutable изменяется на false для обоих dict2 и dict1, хотя мы меняем его только для dict2. Это потому, что мы изменили значение изменяемой части словаря в dict1. Когда мы выполняем .copy() над словарем, по умолчанию выполняется только неглубокая копия, что означает, что он копирует все неизменяемые значения в новый словарь, но не копирует изменяемые значения, а только ссылается на них.

Конечным решением является выполнение .deepycopy() of dict1 для создания совершенно нового отдельного словаря со всем скопированным внутри него, включая изменяемые значения.

>>>import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = copy.deepcopy(dict1)
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> id(dict1)
140641196228824
>>> id(dict2)
140641197662072
>>> id(dict1["key2"])
140641178056312
>>> id(dict2["key2"])
140641197662000
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': True}}

Как вы можете видеть, идентификаторы отличаются, что означает, что dict2 это совершенно новый словарь, содержащий просто копии элементов из dict1.

Deepcopy необходимо использовать всякий раз, когда вы хотите изменить любое из изменяемых значений, не затрагивая исходный словарь. Если нет, вы можете использовать shallow copy . Deepcopy работает медленно, поскольку рекурсивно копирует любые вложенные значения в исходный словарь, а также требует дополнительной памяти.

python dictionary