← Назад к вопросам

Является ли slicing списка shallow или deep копией в Python?

2.0 Middle🔥 181 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Slicing списка: shallow copy

Slicing (срезание) списка создаёт shallow copy (поверхностную копию). Это значит, что создаётся новый список с новыми ссылками на элементы, но сами элементы (если это объекты) не копируются. Это важное различие, которое часто путают разработчики.

Основное понимание

# Slicing создаёт новый список
original = [1, 2, 3, 4, 5]
sliced = original[1:4]

print(f"original: {original}")
print(f"sliced: {sliced}")
print(f"Это разные объекты: {original is sliced}")  # True - разные объекты

# Но это shallow copy для объектов
nested = [[1, 2], [3, 4], [5, 6]]
sliced_nested = nested[0:2]

print(f"nested и sliced_nested - разные списки: {nested is sliced_nested}")  # True
print(f"Но элементы - одни и те же: {nested[0] is sliced_nested[0]}")  # True!

Shallow copy: проблемы при изменении

# Проблема 1: Изменение вложенного объекта
nested = [[1, 2], [3, 4], [5, 6]]
sliced = nested[0:2]

# Изменяем вложенный список через sliced
sliced[0][0] = 999

print(f"nested: {nested}")  # [[999, 2], [3, 4], [5, 6]]
print(f"sliced: {sliced}")  # [[999, 2], [3, 4]]
# Изменение повлияло на оригинальный список!

# Проблема 2: С простыми типами это не проблема
original = [1, 2, 3, 4, 5]
sliced = original[1:4]

sliced[0] = 999

print(f"original: {original}")  # [1, 2, 3, 4, 5] - не изменился
print(f"sliced: {sliced}")  # [999, 3, 4]
# Потому что целые числа immutable (неизменяемы)

Сравнение: слайсинг vs присваивание

# Слайсинг создаёт новый объект
original = [1, 2, 3]
sliced = original[:]  # или original[0:len(original)]

print(f"original is sliced: {original is sliced}")  # False - разные объекты

# Присваивание - это просто новая ссылка на тот же объект
reference = original

print(f"original is reference: {original is reference}")  # True - один объект

# Изменение через reference влияет на original
reference[0] = 999
print(f"original: {original}")  # [999, 2, 3]
print(f"reference: {reference}")  # [999, 2, 3]

Shallow copy в деталях

# Shallow copy копирует только первый уровень
original = {
    "name": "Alice",
    "hobbies": ["reading", "coding"]
}

# Через слайсинг списка (для списков)
original_list = [["a", "b"], ["c", "d"]]
sliced_list = original_list[:]  # Shallow copy

# Через copy() метод (для словарей)
import copy
shallow_dict = copy.copy(original)

print(f"original is shallow_dict: {original is shallow_dict}")  # False
print(f"original[hobbies] is shallow_dict[hobbies]: {original[hobbies] is shallow_dict[hobbies]}")  # True!

# Изменение nested структуры влияет на обе копии
shallow_dict["hobbies"].append("gaming")

print(f"original: {original}")
# {name: Alice, hobbies: [reading, coding, gaming]}
print(f"shallow_dict: {shallow_dict}")
# {name: Alice, hobbies: [reading, coding, gaming]}

Deep copy для полной независимости

import copy

# Deep copy копирует всё рекурсивно
original = {
    "name": "Alice",
    "hobbies": ["reading", "coding"],
    "address": {"city": "NYC", "zip": "10001"}
}

deep = copy.deepcopy(original)

print(f"original is deep: {original is deep}")  # False
print(f"original[hobbies] is deep[hobbies]: {original[hobbies] is deep[hobbies]}")  # False!
print(f"original[address] is deep[address]: {original[address] is deep[address]}")  # False!

# Изменения в deep не влияют на original
deep["hobbies"].append("gaming")
deep["address"]["city"] = "Boston"

print(f"original[hobbies]: {original[hobbies]}")  # [reading, coding]
print(f"deep[hobbies]: {deep[hobbies]}")  # [reading, coding, gaming]

print(f"original[address]: {original[address]}")  # {city: NYC, zip: 10001}
print(f"deep[address]: {deep[address]}")  # {city: Boston, zip: 10001}

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

# Пример 1: Различные способы создать shallow copy списка
original = [1, 2, 3, 4, 5]

# Способ 1: Слайсинг
copy1 = original[:]  # Shallow copy

# Способ 2: Конструктор list()
copy2 = list(original)  # Shallow copy

# Способ 3: copy модуль
import copy
copy3 = copy.copy(original)  # Shallow copy

print(all(copy is not original and copy == original for copy in [copy1, copy2, copy3]))

# Пример 2: Слайсинг с шагом
original = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

sliced1 = original[::2]  # [0, 2, 4, 6, 8]
sliced2 = original[1:8:2]  # [1, 3, 5, 7]
sliced3 = original[::-1]  # Реверс: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

print(f"[::2]: {sliced1}")
print(f"[1:8:2]: {sliced2}")
print(f"[::-1]: {sliced3}")

# Пример 3: Использование слайсинга для операций
data = [1, 2, 3, 4, 5]

# Первые N элементов
first_three = data[:3]  # [1, 2, 3]

# Последние N элементов
last_two = data[-2:]  # [4, 5]

# Всё кроме первого и последнего
middle = data[1:-1]  # [2, 3, 4]

print(f"first_three: {first_three}")
print(f"last_two: {last_two}")
print(f"middle: {middle}")

Когда это важно

# Случай, когда shallow copy создаёт проблемы
class Student:
    def __init__(self, name, grades):
        self.name = name
        self.grades = grades

students = [
    Student("Alice", [80, 85, 90]),
    Student("Bob", [75, 80, 85])
]

# Shallow copy списка студентов
students_copy = students[:]  # или students.copy()

# Изменение оценок через копию влияет на оригинал!
students_copy[0].grades.append(95)

print(f"Оригинал Alice grades: {students[0].grades}")  # [80, 85, 90, 95]
print(f"Copy Alice grades: {students_copy[0].grades}")  # [80, 85, 90, 95]

# Решение: используйте deep copy
import copy
students_deep = copy.deepcopy(students)

students_deep[0].grades.append(100)

print(f"Оригинал Alice grades: {students[0].grades}")  # [80, 85, 90, 95]
print(f"Deep copy Alice grades: {students_deep[0].grades}")  # [80, 85, 90, 95, 100]

Выводы

  • Слайсинг (list[:]) создаёт shallow copy — новый контейнер, но ссылки на элементы остаются теми же
  • Shallow copy безопасна для неизменяемых типов (int, str, tuple)
  • Shallow copy может привести к неожиданным изменениям, если элементы — это объекты или коллекции
  • Deep copy (copy.deepcopy()) создаёт полностью независимую копию со всеми вложенными объектами
  • Выбор между shallow и deep copy зависит от структуры данных и требований приложения
Является ли slicing списка shallow или deep копией в Python? | PrepBro