Учебник по 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]
"""

После изменения первого индекса в нашем исходном списке мы печатаем наши четыре скопированных списка, и только глубоко скопированный список сохраняет свои исходные значения.

В заключение, когда вы думаете о фотокопировании списка, это функциональный пример глубокой копии - была создана отдельная, полностью отдельная сущность. При разработке концепции поверхностного копирования подумайте об облачном документе, к которому могут получить доступ несколько объектов; однако, когда кто-то меняет «свою копию», все остальные тоже принимают обновление.

Спасибо за внимание. Поделитесь своим опытом, вопросами и отзывами ниже!