W3docs

Словари Python: метод копирования

Все способы копирования словаря в Python — copy(), dict(), {**d} и deepcopy() — с примерами поведения поверхностной и глубокой копии.

В этой главе рассмотрены все стандартные способы копирования словаря Python, объясняется, почему обычное присваивание (=) не является копированием, и когда вместо поверхностной копии необходима глубокая.

Почему словарь нельзя скопировать с помощью =

Присваивание словаря новой переменной не создаёт копию — оно создаёт вторую ссылку на тот же объект. Любое изменение, сделанное через любую из переменных, затрагивает один и тот же словарь.

original = {'a': 1, 'b': 2}
alias = original          # same object, not a copy

alias['c'] = 3
print(original)           # {'a': 1, 'b': 2, 'c': 3}  — original changed!

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

Поверхностная копия и глубокая копия

Прежде чем рассматривать методы, полезно понять два вида копирования:

ВидЧто копируетсяВложенные изменяемые объекты
Поверхностная копияПары ключ-значение верхнего уровняСсылки используются совместно — изменение в одном словаре затрагивает другой
Глубокая копияКаждый объект на каждом уровне вложенностиПолностью независима — общих ссылок нет

Для плоских словарей (значения — строки, числа, None, boolean) поверхностной копии всегда достаточно. Если словарь содержит списки, множества или другие словари в качестве значений, следует рассмотреть глубокую копию.

Метод 1: dict.copy()

Встроенный метод copy() возвращает новый словарь, являющийся поверхностной копией исходного. Это наиболее идиоматичный выбор для плоских словарей.

Синтаксис

new_dict = original_dict.copy()

Создание поверхностной копии словаря в Python

python— editable, runs on the server

Добавление или удаление ключа в new_dict не затронет original_dict, поскольку копия верхнего уровня независима.

Обновление ключей верхнего уровня в скопированном словаре

python— editable, runs on the server

Метод 2: конструктор dict()

Передача существующего словаря в конструктор dict() создаёт поверхностную копию так же, как copy().

original_dict = {'name': 'Alice', 'age': 30}
new_dict = dict(original_dict)

new_dict['age'] = 31
print(original_dict)   # {'name': 'Alice', 'age': 30}
print(new_dict)        # {'name': 'Alice', 'age': 31}

dict() удобен, когда нужно явно создать словарь из другого отображения или совместить ключевые аргументы с существующим словарём:

defaults = {'color': 'blue', 'size': 'M'}
custom = dict(defaults, size='L', weight='light')
print(custom)
# {'color': 'blue', 'size': 'L', 'weight': 'light'}

Метод 3: распаковка словаря {**d}

Оператор распаковки ** объединяет словарь в новый словарный литерал. Для простого копирования он ведёт себя идентично copy(), но также позволяет объединить несколько словарей или переопределить отдельные ключи в одном выражении.

original_dict = {'a': 1, 'b': 2}
new_dict = {**original_dict}

new_dict['c'] = 3
print(original_dict)   # {'a': 1, 'b': 2}
print(new_dict)        # {'a': 1, 'b': 2, 'c': 3}

Копирование с переопределением ключа

config = {'host': 'localhost', 'port': 5432, 'debug': False}
prod_config = {**config, 'host': 'db.example.com', 'debug': False}
print(prod_config)
# {'host': 'db.example.com', 'port': 5432, 'debug': False}

Как и copy(), это поверхностная копия — вложенные изменяемые объекты по-прежнему используются совместно.

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

Все три метода выше создают поверхностные копии. Если значение само является изменяемым объектом (например, списком), и оригинал, и копия хранят ссылку на один и тот же внутренний объект.

Обновление изменяемых значений внутри скопированного словаря

python— editable, runs on the server

Оба словаря отражают изменение, поскольку new_dict['key1'] и original_dict['key1'] указывают на один и тот же объект-список. Это ожидаемое поведение поверхностной копии — это не ошибка.

Метод 4: copy.deepcopy() для полной независимости

Когда необходима полная изоляция — включая вложенные списки, множества и словари — используйте copy.deepcopy() из стандартного модуля copy. Функция рекурсивно копирует каждый объект в структуре.

Глубокая копия в Python

python— editable, runs on the server

deepcopy() работает с произвольно вложенными структурами и даже с самореферентными объектами. Её недостатки — скорость и использование памяти: она медленнее поверхностной копии, поскольку должна обойти и продублировать весь граф объектов.

Выбор подходящего метода

СитуацияРекомендуемый метод
Плоский словарь (без вложенных изменяемых объектов)dict.copy() или {**d}
Объединение / переопределение ключей при копировании{**d, key: value} или dict(d, key=value)
Вложенные изменяемые объекты, нужна полная независимостьcopy.deepcopy()
Преобразование другого отображения в копию словаряdict(mapping)

Резюме

  • Оператор = создаёт псевдоним, а не копию.
  • dict.copy(), dict() и {**d} создают поверхностные копии — ключи верхнего уровня независимы, но вложенные изменяемые объекты используются совместно.
  • copy.deepcopy() создаёт глубокую копию — каждый объект на каждом уровне вложенности дублируется.
  • Для плоских словарей предпочтительнее использовать dict.copy() для наглядности.
  • Используйте {**d, overrides}, когда нужно скопировать и изменить словарь в одном выражении.

Смотрите также: Методы словарей · Вложенные словари · Перебор словарей

Практика

Практика
Which of the following methods can be used to copy Python Dictionaries?
Which of the following methods can be used to copy Python Dictionaries?
Was this page helpful?