Учебник по Python с примерами кода
Когда я обучаю программированию, я использую аналогию для копирования списка - это делать ксерокопию. Это простой наглядный пример, который может понять каждый. Но что еще более важно, у этой аналогии есть серьезный недостаток - намеренно. В отличие от фотокопии, есть дополнительный компонент для копирования списков и любой другой сложной структуры данных: мелкое копирование против глубокого копирования.
В этом руководстве мы продемонстрируем как поверхностное, так и глубокое копирование, чтобы подчеркнуть разницу. Мелкое копирование - более простой процесс, поэтому мы предложим для этого три различных метода.
Стартовый код
Для начала нам понадобится начальный стартовый код. Мы определяем простой класс с одним атрибутом name
. Метод __init__
выполняется при создании экземпляра класса, а метод __repr__
отвечает за определение момента печати экземпляра класса.
class Person: def __init__(self, name): self.name = name def __repr__(self): return self.nameteam = [Person("Cloud"), Person("Tifa"), Person("Yuffie)]
Мы собираемся создать список с именем team
с тремя экземплярами нашего класса. Это будет использоваться в качестве основы для демонстрации разницы между мелкой и глубокой копией.
Как сделать неглубокую копию
Когда вы неглубоко копируете список, вы создаете новый список, который сохраняет ссылки из исходного списка. Это означает, что у нас есть два списка, которые указывают на одно и то же место в памяти.
Двойная ссылка не является проблемой для примитивных значений, таких как строки и целые числа; однако для сложных данных, таких как классы, мы можем столкнуться с непредвиденными последствиями при изменении значений списка.
Прежде чем мы погрузимся во все это, есть три способа выполнить поверхностное копирование.
# The .copy() Method team1 = team.copy()# Slice Notation team2 = team[:]# Splat Operator team3 = [*team]
Для удобства списки имеют предопределенный метод с именем .copy()
для простой неглубокой копии. Нотация срезов также может использоваться для функционального создания неглубокой копии и является полезной нотацией для ознакомления, если вам нужно взять части списков. Наконец, оператор splat может использоваться для распаковки нашего исходного списка в новый и полезен для копирования и расширения списка.
Теперь вернемся к проблеме с неглубокой копией. Поскольку оба списка указывают на один и тот же экземпляр объекта, при изменении объекта в одном списке он также будет изменен в другом. Подразумевается, что нашим скопированным списком нельзя безнаказанно манипулировать.
Как сделать глубокую копию
Глубокая копия необходима для создания списка, действительно независимого от его составителя. В отличие от методов поверхностного копирования, глубокая копия требует использования импортированной библиотеки - взгляните на начальный код, если вы его пропустили.
В библиотеке copy
мы импортируем функцию deepcopy()
. Отсюда легко использовать. Давайте продемонстрируем глубокую копию, а затем, наконец, увидим разницу между мелкой и глубокой, изменив нашу исходную команду.
team4 = deepcopy(team)team[0].name = "Cid"print(team1, team2, team3, team4, sep="\n") """ [Cid, Tifa, Yuffie] [Cid, Tifa, Yuffie] [Cid, Tifa, Yuffie] [Cloud, Tifa, Yuffie] """
После изменения первого индекса в нашем исходном списке мы печатаем наши четыре скопированных списка, и только глубоко скопированный список сохраняет свои исходные значения.
В заключение, когда вы думаете о фотокопировании списка, это функциональный пример глубокой копии - была создана отдельная, полностью отдельная сущность. При разработке концепции поверхностного копирования подумайте об облачном документе, к которому могут получить доступ несколько объектов; однако, когда кто-то меняет «свою копию», все остальные тоже принимают обновление.
Спасибо за внимание. Поделитесь своим опытом, вопросами и отзывами ниже!