Python 使用高级索引的分配是否复制阵列数据?
我正在慢慢地试图理解numpy中的Python 使用高级索引的分配是否复制阵列数据?,python,numpy,copy,Python,Numpy,Copy,我正在慢慢地试图理解numpy中的views和copys之间的区别,以及可变和不可变类型之间的区别 如果我访问数组的一部分,它应该返回一个副本。这似乎是真的: In [1]: import numpy as np In [2]: a = np.zeros((3,3)) In [3]: b = np.array(np.identity(3), dtype=bool) In [4]: c = a[b] In [5]: c[:] = 9 In [6]: a Out[6]: array([[ 0
view
s和copy
s之间的区别,以及可变和不可变类型之间的区别
如果我访问数组的一部分,它应该返回一个副本。这似乎是真的:
In [1]: import numpy as np
In [2]: a = np.zeros((3,3))
In [3]: b = np.array(np.identity(3), dtype=bool)
In [4]: c = a[b]
In [5]: c[:] = 9
In [6]: a
Out[6]:
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
由于c
只是一个副本,因此它不会共享数据,更改它也不会变异a
。然而,这让我感到困惑:
In [7]: a[b] = 1
In [8]: a
Out[8]:
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
所以,看起来,即使我使用高级索引,赋值仍然将左边的东西视为一个视图。显然,第2行中的a
与第6行中的a
是相同的对象/数据,因为变异c
对其没有影响
所以我的问题是:第8行中的a
是与之前相同的对象/数据(当然不包括对角线)还是副本?换句话说,a
的数据是复制到新的a
,还是其数据发生了突变
例如,它是否像:
x = [1,2,3]
x += [4]
或者说:
y = (1,2,3)
y += (4,)
我不知道如何检查这一点,因为无论哪种情况,
a.flags.owndata
都是True
。如果我用一种令人困惑的方式思考这个问题,请随时详细说明或回答不同的问题。是的,它是同一个对象。以下是您检查的方式:
>>> a
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> a2 = a
>>> a[b] = 1
>>> a2 is a
True
>>> a2
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
在Python中为某个表达式赋值与读取该表达式的值不同。如果执行c=a[b]
,且在等号右侧有a[b]
,则返回一个新对象。如果执行a[b]=1
,并在等号左侧使用a[b]
,则会修改原始对象
事实上,像
a[b]=1这样的表达式不能更改a
绑定的名称。处理obj[index]=value
的代码只知道对象obj
,而不是用来引用该对象的名称,因此它不能更改该名称所引用的内容。当您执行c=a[b]
时,a.\uu get\u item\uu
将b
作为其唯一参数调用,无论返回什么,都将分配给c
当您执行a[b]=c
时,a.\uuuu setitem\uuuuu
将使用b
和c
作为参数进行调用,返回的任何内容都将被默默地丢弃
因此,尽管有相同的a[b]
语法,但这两个表达式所做的事情不同。您可以子类化ndarray
,重载这两个函数,并使它们的行为不同。在numpy中,默认情况下,前者返回一个副本(如果b
是一个数组),但后者修改a
。这似乎是常见的误解,引用了官方文件:
()
这里的经验法则是:在左值索引(即。
索引放置在赋值的左侧值中),
不创建阵列的视图或副本(因为不需要创建)。
但是,对于常规值,上述创建视图的规则不适用
申请
换句话说,,view
或copy
的概念仅指从numpy
对象检索值的情况。我认为值得在numpy文档中明确指出一个事实,即当用作左值时,即使是高级索引也会修改原始数组。请参阅视图与副本的精彩摘要。