У списков Python срез — это копия: изменили кусок — исходный список цел. У массивов NumPy иначе, и это одна из самых частых неожиданностей для новичков.
Срез смотрит на тот же массив
Срез массива — это представление (view): окно, через которое видны те же самые данные. Своих данных у него нет. Поэтому изменение среза меняет исходный массив:
import numpy as np
prices = np.array([100.0, 250.0, 80.0, 40.0])
first = prices[:2]
first[0] = 0
print(first)
print(prices)[ 0. 250.] [ 0. 250. 80. 40.]
first и prices — два взгляда на одну память. Для сравнения — список:
price_list = [100.0, 250.0, 80.0, 40.0]
part = price_list[:2]
part[0] = 0
print(part)
print(price_list)[0, 250.0] [100.0, 250.0, 80.0, 40.0]
Зачем так сделано: массивы бывают огромными (миллионы чисел), и копировать данные при каждом срезе было бы медленно и расточительно. Представление создаётся мгновенно, сколько бы элементов в нём ни было.
Копия: copy()
Метод copy() создаёт настоящую копию со своими данными. Её можно менять как угодно:
prices = np.array([100.0, 250.0, 80.0, 40.0])
first = prices[:2].copy()
first[0] = 0
print(first)
print(prices)[ 0. 250.] [100. 250. 80. 40.]
В заготовке ниже встретится запись sale[:] = sale * 0.5 — присваивание в срез: новые значения
записываются в те же ячейки памяти, на которые смотрит sale. Подробнее о ней — чуть ниже.
В prices — цены четырёх товаров. Сделайте массив sale — цены первых двух товаров со скидкой 50 %,
а prices оставьте как был. В заготовке уже есть код, но он портит prices — исправьте его.
prices[:2] прямо в исходном массиве.prices[:2].copy().Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
prices = np.array([100.0, 250.0, 80.0, 40.0])
sale = prices[:2]
sale[:] = sale * 0.5Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
prices = np.array([100.0, 250.0, 80.0, 40.0])
sale = prices[:2].copy()
sale[:] = sale * 0.5Что напечатает этот код?
a = np.array([1, 2, 3, 4])
b = a[1:3]
b[0] = 99
print(a)b — окно на элементы a с индексами 1 и 2. b[0] — это a[1], поэтому в a двойка меняется на 99.Когда представление — то, что нужно
Бывает, что изменить часть исходника и нужно. Тогда представление удобно: дали ему короткое имя — и меняете через него:
week_plan = np.full(7, 100)
weekend = week_plan[5:] # суббота и воскресенье
weekend[:] = 0
print(week_plan)[100 100 100 100 100 0 0]
В plan — план продаж по 12 месяцам. Через представление q2 (месяцы с индексами 3, 4, 5 — второй квартал)
увеличьте план второго квартала на 10 %, чтобы изменился и сам plan.
q2 = plan[3:6] — окно на три месяца.q2[:] = q2 * 1.1. Простое q2 = q2 * 1.1 создаст новый массив и plan не тронет.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
plan = np.array([100.0, 110.0, 120.0, 150.0, 160.0, 170.0, 130.0, 120.0, 140.0, 150.0, 160.0, 200.0])
q2 = ...
# увеличьте q2 на 10 % так, чтобы изменился planУпражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
plan = np.array([100.0, 110.0, 120.0, 150.0, 160.0, 170.0, 130.0, 120.0, 140.0, 150.0, 160.0, 200.0])
q2 = plan[3:6]
q2[:] = q2 * 1.1Прежде чем обнулить в scores всё после третьего элемента, сохраните полную резервную копию в backup, затем
обнулите элементы начиная с индекса 3. backup должен остаться прежним.
backup = scores.copy().scores[3:] = 0.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
scores = np.array([12, 15, 9, 20, 17, 11])
backup = ...
# обнулите scores начиная с индекса 3Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
scores = np.array([12, 15, 9, 20, 17, 11])
backup = scores.copy()
scores[3:] = 0Итоги
- Срез массива — представление: те же данные, изменение видно в исходнике.
copy()— независимая копия; нужна, если срез будете менять, а исходник беречь.- Менять данные через представление — присваиванием в него (
v[:] = …);v = …просто даёт имени новый массив. - Подробнее о том, что даёт представление, а что копию, — в справочнике; например, выборка по маске (модуль 4) всегда копия.