Сообщить об ошибке.

Операция присваивания на месте и списки в Python

Списки в Python невероятно хороши. Можно выполнять разные вещи, такие как:

  • объединение нескольких списков с помощью оператора +;
  • создание повторяющегося списка с помощью оператора *;
  • объединение и назначение списков с помощью оператора +=.

Рассмотрим пример того, как оператор + работает с объектом list.

>>> lst = [3, 4, 5, 6, 7]
>>> lst_copy = lst
>>> lst = lst + [8, 9]
>>> lst
# [3, 4, 5, 6, 7, 8, 9]
>>> lst_copy
# [3, 4, 5, 6, 7]

Что произошло: создали список под названием lst, затем создали новый список с именем lst_copy, указав его на lst. Затем изменили lst, добавив к нему [8, 9]. Как и ожидалось, оператор + расширил список lst создав новую последовательность, тогда как lst_copy остался прежним.

В Python можно сократить выражения типа a = a + 1 до a += 1. Вначале было сказано, что со списками можно использовать оператор +=.

Итак, перепишем пример c использованием оператора присваивания на месте +=:

>>> lst = [3, 4, 5, 6, 7]
>>> lst_copy = lst
>>> lst += [8, 9]
>>> lst
# [3, 4, 5, 6, 7, 8, 9]
>>> lst_copy
# [3, 4, 5, 6, 7, 8, 9]

# Да ладно... Не может быть...

Что здесь произошло? Причина такого поведения в том, что, как и другие операторы Python, реализация оператора += определяется классом, который его реализует. То есть для оператора += класс списка определяет магический метод object.__iadd__(self, other), а способ его работы такой же, как у list.extend().

Так почему же был изменен список lst_copy? Потому что это не фактическая копия lst (lst.copy()), а указатель на ячейку в памяти. То есть для списка list (изменяемых последовательностей) оператор += изменяет ее, как говорится "на месте" - в памяти и не создает новую (итоговую) последовательность как с оператором +.

>>> lst = [3, 4, 5, 6, 7]
>>> lst_copy = lst
>>> lst.extend([8, 9])
>>> lst
# [3, 4, 5, 6, 7, 8, 9]
>>> lst_copy
# [3, 4, 5, 6, 7, 8, 9]