Какой вариант, по вашему мнению, будет правильным?
Большинство без проблем отвечают на первые две строки:
numbers * 3 создаёт новый список: [1, 2, 3, 1, 2, 3, 1, 2, 3]
А numbers + [4, 5] объединяет два списка: [1, 2, 3, 4, 5]
Но третья строка уже гораздо интереснее.
[numbers] * 3
Результат выглядит так:
[[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]
Кажется, что Python создал три независимых списка.
Оператор * не копирует вложенные объекты. Он копирует ссылки на них.
В результате все элементы списка указывают на один и тот же объект в памяти.
Это одна из самых частых ошибок
Подобная конструкция регулярно встречается при создании:
- матриц;
- игровых полей;
- двумерных массивов;
- таблиц динамического программирования.
И может привести к очень неожиданным ошибкам.
Как сделать правильно?
Если нужны независимые вложенные списки, используйте генератор списка:
matrix = [[1, 2, 3] for _ in range(3)]
Теперь каждая строка будет отдельным объектом.
💡 Запомните правило
Если используете оператор * со вложенными изменяемыми объектами — подумайте дважды.
Он копирует не сами объекты, а ссылки на них.
Знаете ли вы, что переменные можно менять местами без временной переменной?
Во многих языках программирования для обмена значений приходится использовать дополнительную переменную:
a = 10
b = 20
temp = a
a = b
b = temp
В Python всё гораздо проще:
a = 10
b = 20
a, b = b, a
После выполнения:
a = 20
b = 10
Как это работает?
На самом деле Python сначала формирует кортеж: (b, a)
а затем распаковывает его обратно: a, b = (20, 10)
Поэтому обмен происходит корректно и без потери данных.
Но этим возможности распаковки не ограничиваются
Можно сразу получать несколько значений:
name, age, city = ("Artem", 37, "Moscow")
Или разделять начало и конец последовательности:
first, *middle, last = [1, 2, 3, 4, 5]
Результат:
first -> 1
middle -> [2, 3, 4]
last -> 5
Где это полезно?
✅ Обмен переменных
✅ Возврат нескольких значений из функции
✅ Обработка CSV и таблиц
✅ Работа с координатами
✅ Разбор данных из API
Интересный факт
Многие считают, что это просто красивый синтаксис.
На самом деле распаковка кортежей — одна из ключевых идей Python, которая используется буквально повсюду:
- в циклах через enumerate()
- в zip()
- при возврате нескольких значений из функций
- в pattern matching (Python 3.10+)