Списки в Python невероятно хороши. Можно выполнять разные вещи, такие как:
- объединение нескольких списков с помощью оператора
+
; - создание повторяющегося списка с помощью оператора
*
; - объединение и назначение списков с помощью оператора
+=
.
>>> 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
. Вначале было сказано, что со списками можно использовать оператор +=
.
>>> 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]