Как скопировать словарь и редактировать только копию
Я установил 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 работает медленно, поскольку рекурсивно копирует любые вложенные значения в исходный словарь, а также требует дополнительной памяти.