LINUX.ORG.RU

Странное поведение numpy

 ,


0

3

Не могу понять как это работает

L = numpy.array([1, 2, 3])
def add_val(L, a):
    L = L + a
    print('Local L:', L)

add_val(L, 2)
print('Global L:', L)
Local L: [3 4 5]
Global L: [1 2 3]
L = numpy.array([1, 2, 3])
def add_val(L, a):
    L += a
    print('Local L:', L)

add_val(L, 2)
print('Global L:', L)
Local L: [3 4 5]
Global L: [3 4 5]
L = numpy.array([1, 2, 3])
def add_val(L, a):
    L = L[:]
    L += a
    print('Local L:', L)

add_val(L, 2)
print('Global L:', L)
Local L: [3 4 5]
Global L: [3 4 5]

Почему первый и второй случай так различаются? Что происходит в третьем случае? Почему не копируется массив?

L + a создаёт новый объект и записывает в новую локальную переменную, а L += a работает с глобальным объектом не создавая новую локальную переменную?

uCore
()
Ответ на: комментарий от uCore

Я хотел сказать питон передаёт значения по ссылке(в основном), и L += работает с объектом на который ссылается L.
А L + a создаёт новый объект на который и начинает ссылаться локальная L.

uCore
()

Сделай L = L[1:], а после L += a увидишь результат ещё интереснее (:

uCore
()

Почему не копируется массив?

нет под рукой питона чтобы проверить, но попробуй с deepcopy. Скорее всего ты просто создал новый масив, но наполнил его ссылками на объекты из старого

Dred ★★★★★
()
Ответ на: комментарий от Archer73

А почему L = L[:] не создает копии объекта через срез

Попробуй явно указать .copy()

alienclaster ★★★
()
Ответ на: комментарий от Dred

Скорее всего ты просто создал новый масив, но наполнил его ссылками на объекты из старого

нет там никаких объектов. это numpy. там внизу тупо массив int-ов, обычных си-шных интов (с точностью до разрядности)

MyTrooName ★★★★★
()
Последнее исправление: MyTrooName (всего исправлений: 2)
Ответ на: комментарий от Archer73

почему L = L[:] не создает копии объекта через срез

по определению. слайс массива в numpy указывает в ту же область памяти, в отличие от слайса питоновских списков, например, которые делают копию

MyTrooName ★★★★★
()
Последнее исправление: MyTrooName (всего исправлений: 4)
Ответ на: комментарий от uCore

L + a создаёт новый объект, который будет записан в уже существующую локальную переменную L (L = L + a), а L += a работает с глобальным объектом не создавая новую локальную переменную?

примерно

L + a (__add__) создаёт новый массив, который будет записан в уже существующую локальную переменную L, а L += a (__iadd__) работает с объектом, переданным в параметре L, и L продолжает указывать на тот же массив, но уже измененный

MyTrooName ★★★★★
()
Последнее исправление: MyTrooName (всего исправлений: 4)
Ответ на: комментарий от greenman

если ты про __add__ и __iadd__, то это нормальная семантика для питона. про это должно быть где-то и в доках numpy, но естественно предполагать именно такое поведение по умолчанию

https://docs.python.org/3/reference/datamodel.html#object.__iadd__

единственная неочевидность - при отсутствии метода __iadd__ у объекта, будет вызван метод __add__, и значение локальной переменной будет перезаписано, т.е. L += a будет равносильно L = L + a. Но __iadd__ в доках присутствует

MyTrooName ★★★★★
()
Последнее исправление: MyTrooName (всего исправлений: 1)
Ответ на: комментарий от MyTrooName

Это был не вопрос. Точнее это был вопрос ТСу, на подумать.
Подробности про __add__ и __iadd__ хоть и читал, но у меня успели выветриться.
Тот-же это объект или новый я проверял с помощью id(L).

uCore
()
Ответ на: комментарий от MyTrooName

А причем здесь лист или не лист? Я дал ссылку на пост, где дан ответ что такое numpy array и как себя ведет его срез. Промотать-то можно этот пост немного?

Booster ★★
()
Последнее исправление: Booster (всего исправлений: 1)
Ответ на: комментарий от Booster

каюсь.

а так, там можно на ответ прямую ссылку дать

MyTrooName ★★★★★
()

Меня вот тоже временами вымораживает такое поведение списков... Тут только надо привыкнуть и будет хорошо.

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от Archer73

Ну, во-первых это не список, а нампайный массив. Во-вторых, нампай нацелен на оптимизацию, и я думаю, что там вместо фактического копирования создается структура, которая указывает на старый массив, прост имеет другие индексы начала и конца. А так как ты используешь мутабельную операцию +=, то вот и старый массив задевается.

Aswed ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.