W3docs

Копирование списков

Все способы копирования списка в Python: ловушка присваивания, срезы, copy(), list() и deepcopy() — с примерами и объяснениями.

Списки в Python (lists) являются изменяемыми, а это значит, что присваивание списка новой переменной не создаёт копию — оба имени указывают на один и тот же объект. На этой странице рассматриваются все надёжные способы копирования списка, разница между поверхностной и глубокой копией, а также ситуации, когда каждый из подходов является правильным выбором.

Ловушка присваивания

Распространённая ошибка — использование оператора = в ожидании получить независимую копию:

Почему оператор = не копирует список

python— editable, runs on the server

И original, и alias указывают на один и тот же объект списка в памяти. Любое изменение, сделанное через одно имя, немедленно отображается через другое.

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

Методы поверхностного копирования

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

Метод copy()

Метод copy() — наиболее явный и читаемый подход:

Копирование списка методом copy()

original = ["apple", "banana", "cherry"]
copy_of = original.copy()

copy_of.append("date")
print(original)   # Output: ['apple', 'banana', 'cherry']
print(copy_of)    # Output: ['apple', 'banana', 'cherry', 'date']

Теперь два списка независимы: добавление элемента в copy_of не влияет на original.

Срезовая нотация [:]

Срезовая нотация — питоничный способ быстрого копирования всего списка:

Копирование списка с помощью срезовой нотации

original = [10, 20, 30, 40]
copy_of = original[:]

copy_of[0] = 99
print(original)   # Output: [10, 20, 30, 40]
print(copy_of)    # Output: [99, 20, 30, 40]

[:] читается как «взять каждый элемент от начала до конца», что создаёт новый список, содержащий эти элементы.

Конструктор list()

Передача существующего списка в list() также создаёт поверхностную копию:

Копирование списка с помощью конструктора list()

original = [1, 2, 3]
copy_of = list(original)

copy_of.append(4)
print(original)   # Output: [1, 2, 3]
print(copy_of)    # Output: [1, 2, 3, 4]

Это особенно удобно, когда нужно одновременно преобразовать другой итерируемый объект (например, кортеж) в список.

Когда поверхностных копий недостаточно

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

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

python— editable, runs on the server

Оба списка разделяют одни и те же внутренние объекты [1, 2] и [3, 4]. Изменение original[0][0] модифицирует этот общий внутренний список, поэтому изменение отражается и в shallow.

Глубокое копирование

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

Глубокое копирование вложенного списка с помощью copy.deepcopy()

import copy

original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)

original[0][0] = 99       # Mutate the nested list

print(original)   # Output: [[99, 2], [3, 4]]
print(deep)       # Output: [[1, 2], [3, 4]]  <- unchanged

deep хранит собственные копии внутренних списков, поэтому изменения original никак на него не влияют.

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

МетодСоздаёт новый список?Копирует вложенные объекты?Лучше всего для
Присваивание =НетНетТолько псевдонимы
copy()ДаНет (поверхностная)Плоские списки
Срез [:]ДаНет (поверхностная)Плоские списки
list()ДаНет (поверхностная)Плоские списки / итерируемые
copy.deepcopy()ДаДаВложенные структуры

Практические примеры

Все методы поверхностного копирования вместе

original = [1, 2, 3]

a = original.copy()    # method
b = original[:]        # slice
c = list(original)     # constructor

original.append(4)

print(a)  # Output: [1, 2, 3]
print(b)  # Output: [1, 2, 3]
print(c)  # Output: [1, 2, 3]

Все три создают независимые копии — ни одна из них не отражает последующий append(4).

Копирование списка словарей

Словари — это изменяемые объекты. Поверхностная копия списка словарей разделяет эти объекты dict:

import copy

records = [{"name": "Alice", "score": 90}, {"name": "Bob", "score": 85}]
shallow = records.copy()
deep    = copy.deepcopy(records)

records[0]["score"] = 0

print(shallow[0])   # Output: {'name': 'Alice', 'score': 0}   <- shared dict
print(deep[0])      # Output: {'name': 'Alice', 'score': 90}  <- independent copy

Если элементы являются изменяемыми объектами и требуется полная независимость, всегда используйте deepcopy().

Заключение

Списки Python изменяемы, поэтому оператор = создаёт псевдоним, а не копию. Для плоских списков любой из методов поверхностного копирования — copy(), [:] или list() — подходит одинаково хорошо. Когда списки содержат вложенные изменяемые объекты, используйте copy.deepcopy() для обеспечения полной независимости.

Для изучения связанных операций со списками см. List Methods, Add List Items и Remove List Items. При копировании словарей применяется то же разграничение между поверхностным и глубоким копированием — см. Copy Dictionaries.

Практика

Практика
In Python, which operation(s) can be used to copy a list?
In Python, which operation(s) can be used to copy a list?
Was this page helpful?