为什么对看似数据副本的操作会修改原始数据?

2024-04-25 23:11:22 发布

您现在位置:Python中文网/ 问答频道 /正文

让我们引用纽比手册:https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#advanced-indexing

Advanced indexing is triggered when the selection object, obj, is a non-tuple sequence object, an ndarray (of data type integer or bool), or a tuple with at least one sequence object or ndarray (of data type integer or bool). There are two types of advanced indexing: integer and Boolean.

Advanced indexing always returns a copy of the data (contrast with basic slicing that returns a view).

然后,对高级索引返回的内容进行操作时,绝不应修改原始数组。事实上:

import numpy as np

arr = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
indexes = np.array([3, 6, 4])

slicedArr = arr[indexes]
slicedArr *= 5
arr

打印:

^{pr2}$

然而,情况并非总是如此。奇怪的是,如果我不将[]运算符返回的内容保存到中间变量,那么我将以某种方式对原始数组进行操作。请考虑这个例子:

import numpy as np

arr = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
indexes = np.array([3, 6, 4])

arr[indexes] *= 5
arr

打印:

array([  0,  10,  20, 150, 200,  50, 300,  70,  80,  90])

我不抱怨。实际上,这是我的救命稻草。然而,我不明白为什么这是有效的,我真的很想了解这一点。在

据我所知,只要我写arr[indexes]我就在创建数组的一个副本;因此后续的*= 5应该在这个副本上操作,而不是在原始数组上操作。但是,应该丢弃此计算的结果,因为它不会写入任何变量。在

但显然我错了。在

我的误会在哪里?在


Tags: orofnumpydataobjectisnpinteger
2条回答

While语句

a = expr

以及

^{pr2}$

看起来很相似,其实根本不同。第一个将名称“a”绑定到expr。 第二个或多或少是equivalent到{}。__setitem__实际做什么取决于实现它的人,但是传统的语义是用x所指示的位置用expr更新容器对象{}。 特别是,不创建中间对象“表示a[x]”。在

为了完整起见,a[x]如果它不在语法上看起来像是赋值的l.h.s.,那么它或多或少等同于a.__getitem__(x)。在

更新以回答后续问题(执行a[x] *= 5时会发生什么情况?)让我们用仪器来测试相关的方法,这样我们就能知道发生了什么。下面,__imul__是就地乘法的“神奇方法”:

^{3}$

印刷品:

setitem Ellipsis
getitem ([1, 2], [4, 2])
imul 5
setitem ([1, 2], [4, 2])

关键是

Advanced indexing always returns a copy of the data

在第二个示例中,没有使用索引返回任何内容。您只使用索引来修改值。所以你要修改的对象就是原始对象。不是拷贝。在

相关问题 更多 >