我不确定我理解为什么这不起作用:
a = np.zeros((10, ))
# first slicing array
pos1 = np.zeros((10, ), dtype=np.bool)
pos1[::2] = True
a[pos1] = 1.
print a
# returns [ 1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]
# second slicing array
pos2 = np.zeros((5, ), dtype=np.bool)
pos2[::2] = True
a[pos1][pos2] = 2.
print a
# still returns [ 1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]
为什么第二次切片不会影响整个阵列?
我认为a[pos1]
只是一个"视图"原始数组的子部分...我错过了什么?
(这个例子只是一个没有实际用处的简单例子,它只是试图理解我使用这种语法的原因很多而且我没有预料到这个结果)
答案 0 :(得分:2)
与最近Numpy doesn't change value of an array element after masking
中的问题相同您正在使用布尔掩码,因此a[pos1]
是副本,而不是切片。
第一组有效,因为它是对__setitem__
的直接调用:
a[pos1] = 1.
a.__setitem__(pos1) = 1
第二个不是因为set
适用于a[pos1]
,副本:
a[pos1][pos2] = 2.
a.__getitem__(pos1).__setitem__(pos2)
a[::2][pos2]=3
确实有效,因为a[::2]
是一个切片 - 即使它生成的值与a[pos1]
相同。
检查某些内容是副本还是视图的一种方法是查看数组的数据指针
a.__array_interface__['data']
a[pos1].__array_interface__['data'] # will be different
a[::2].__array_interface__['data'] # should be the same
答案 1 :(得分:0)
当我们定义以下三个函数时,请查看python字节代码(dis的输出):
In [187]: def b():
a[pos1][pos2]=2
return a
In [188]: dis.dis(b)
2 0 LOAD_CONST 1 (2)
3 LOAD_GLOBAL 0 (a)
6 LOAD_GLOBAL 1 (pos1)
9 BINARY_SUBSCR
10 LOAD_GLOBAL 2 (pos2)
13 STORE_SUBSCR
3 14 LOAD_GLOBAL 0 (a)
17 RETURN_VALUE
In [189]: b()
Out[189]: array([ 1., 0., 1., 0., 1., 0., 1., 0., 1., 0.])
In [190]: def c():
e=a.copy()
e[pos1][pos2]=2
return e
In [191]: dis.dis(c)
2 0 LOAD_GLOBAL 0 (a)
3 LOAD_ATTR 1 (copy)
6 CALL_FUNCTION 0
9 STORE_FAST 0 (e)
3 12 LOAD_CONST 1 (2)
15 LOAD_FAST 0 (e)
18 LOAD_GLOBAL 2 (pos1)
21 BINARY_SUBSCR
22 LOAD_GLOBAL 3 (pos2)
25 STORE_SUBSCR
4 26 LOAD_FAST 0 (e)
29 RETURN_VALUE
In [191]: c()
Out[191]: array([ 1., 0., 1., 0., 1., 0., 1., 0., 1., 0.])
In [192]: def d():
f=a[pos1]
f[pos2]=2
return f
In [193]: dis.dis(d)
2 0 LOAD_GLOBAL 0 (a)
3 LOAD_GLOBAL 1 (pos1)
6 BINARY_SUBSCR
7 STORE_FAST 0 (f)
3 10 LOAD_CONST 1 (2)
13 LOAD_FAST 0 (f)
16 LOAD_GLOBAL 2 (pos2)
19 STORE_SUBSCR
4 20 LOAD_FAST 0 (f)
23 RETURN_VALUE
In [194]: d()
Out[194]: array([ 2., 1., 2., 1., 2.])
从反汇编代码中,每次执行a[pos1][pos2]=2
赋值时,它确实存储在堆栈的顶部,但随后返回全局(情况1)或本地(情况2)变量。
当您拆分操作时(案例3),解释器似乎突然想起它只是将值存储在堆栈中而不需要重新加载它。