Нашли ошибку?
Скачать чистый
урок 3 из 5≈ 15 минупражнения: 0 из 3

Срез — это окно

Срез не копирует данные, а смотрит на тот же массив — изменив срез, вы меняете исходник. Когда это удобно, когда опасно и как сделать копию.

Python запустится при первом выполнении

У списков 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. Подробнее о ней — чуть ниже.

[ ]Упражнение 1Скидка без порчи прайса решено

В prices — цены четырёх товаров. Сделайте массив sale — цены первых двух товаров со скидкой 50 %, а prices оставьте как был. В заготовке уже есть код, но он портит prices — исправьте его.

prices = np.array([100.0, 250.0, 80.0, 40.0])
sale = prices[:2]
sale[:] = sale * 0.5

Вопрос

Что напечатает этот код?

a = np.array([1, 2, 3, 4])
b = a[1:3]
b[0] = 99
print(a)

Когда представление — то, что нужно

Бывает, что изменить часть исходника и нужно. Тогда представление удобно: дали ему короткое имя — и меняете через него:

[ ]Обнулить выходные в плане
week_plan = np.full(7, 100)
weekend = week_plan[5:]   # суббота и воскресенье
weekend[:] = 0
print(week_plan)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
[100 100 100 100 100   0   0]
[ ]Упражнение 2Премия второму кварталу решено

В plan — план продаж по 12 месяцам. Через представление q2 (месяцы с индексами 3, 4, 5 — второй квартал) увеличьте план второго квартала на 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 = ...
# увеличьте q2 на 10 % так, чтобы изменился plan

[ ]Упражнение 3Резервная копия решено

Прежде чем обнулить в scores всё после третьего элемента, сохраните полную резервную копию в backup, затем обнулите элементы начиная с индекса 3. backup должен остаться прежним.

scores = np.array([12, 15, 9, 20, 17, 11])
backup = ...
# обнулите scores начиная с индекса 3

Итоги

  • Срез массива — представление: те же данные, изменение видно в исходнике.
  • copy() — независимая копия; нужна, если срез будете менять, а исходник беречь.
  • Менять данные через представление — присваиванием в него (v[:] = …); v = … просто даёт имени новый массив.
  • Подробнее о том, что даёт представление, а что копию, — в справочнике; например, выборка по маске (модуль 4) всегда копия.

Подробнее в справочнике

Нашли ошибку?