Почему += для списка работает не как +?
Сегодня писал код и случайно наткнулся на странность:
python a = [1, 2, 3] b = a a += [4, 5] print(b) # [1, 2, 3, 4, 5]
a = [1, 2, 3] b = a a = a + [4, 5] print(b) # [1, 2, 3]
Я знаю, что списки мутабельны, но почему += меняет исходный объект, а + создаёт новый? Когда какой вариант использовать?
1 ответ
Вся соль в том, что += для списка и + — это две разные операции, а не одна и та же с сокращением.
+ (a = a + [4, 5]) вызывает __add__: создаётся новый список и присваивается имени a. Старый объект, на который всё ещё смотрит b, не тронут — поэтому b остаётся [1, 2, 3].
+= (a += [4, 5]) для списков вызывает __iadd__: он меняет существующий список на месте (по сути a.extend([4, 5])) и возвращает тот же объект. А так как b = a — это два имени для одного списка, b видит изменение: [1, 2, 3, 4, 5].
Короче: + — новый объект, += — мутация на месте. Отсюда правило:
- список кто-то ещё держит (как
b) и трогать его не надо →+илиa = a + [...]; - хочешь именно дописать в существующий список →
+=/.extend(), без лишней копии и быстрее.
С неизменяемыми типами (числа, строки, кортежи) разницы не видно: там += всё равно создаёт новый объект, потому что менять на месте нечего. Путаница именно из-за мутабельности списков.