arr = np.arange(0,11)
slice_of_arr = arr[0:6]
slice_of_arr[:]=99
# slice_of_arr returns
array([99, 99, 99, 99, 99, 99])
# arr returns
array([99, 99, 99, 99, 99, 99, 6, 7, 8, 9, 10])
如上所示,您无法直接更改slice_of_arr
的值,因为它是arr
的视图,而不是新变量。
我的问题是:
.copy
再分配值时,这不是很乏味吗?.copy
?如何更改NumPy的默认行为?答案 0 :(得分:2)
我认为您在其他评论中也有答案,但更具体地说:
1.a。为什么NumPy这样设计?
因为创建视图而不是创建整个数组(线性时间)要更快(固定时间)。
1.b。每次需要复制然后分配值时,都不会很乏味吗?
实际上,创建副本并不常见。所以不,这并不乏味。即使起初可能会感到惊讶,但这种设计还是很好的。
2.a。我能做些什么来摆脱.copy的问题?
如果不使用实际代码,我无法真正分辨。在给出的玩具示例中,无法避免创建副本,但是在实际代码中,通常将函数应用于数据,这些函数会返回另一个数组,因此不需要副本。
您能否举一个需要重复调用.copy
的真实代码示例?
2.b。如何更改NumPy的默认行为?
你不能尝试习惯它,您会发现它功能强大。
答案 1 :(得分:1)
What does (numpy) __array_wrap__ do?
讨论ndarray
子类和__array_wrap__
之类的钩子。 np.array
获取copy
参数,强制结果为副本,即使其他注意事项不需要它也是如此。 ravel
返回一个视图,flatten
一个副本。因此,构建强制复制的ndarray
子类可能也许并不太困难。它可能涉及修改像__array_wrap__
这样的钩子。
或者可能修改.__getitem__
方法。与slice_of_arr = arr[0:6]
中的索引相关的是对__getitem__
的调用。对于ndarray
,这是编译的,但是对于一个屏蔽数组,它可以用作示例的python代码:
/usr/lib/python3/dist-packages/numpy/ma/core.py
可能就像
一样简单def __getitem__(self, indx):
"""x.__getitem__(y) <==> x[y]
"""
# _data = ndarray.view(self, ndarray) # change to:
_data = ndarray.copy(self, ndarray)
dout = ndarray.__getitem__(_data, indx)
return dout
但我怀疑,当你开发并完全测试这样一个子类时,你可能会爱上默认的无副本方法。虽然这个视图复制业务引起了许多新人的注意(特别是如果来自MATLAB),我还没有看到有经验的用户提出的投诉。看看其他numpy SO问题;你不会看到很多copy()
个电话。
即使是普通的Python用户也会问自己,引用或切片是否是副本,以及某些内容是否可变。
例如列表:
In [754]: ll=[1,2,[3,4,5],6]
In [755]: llslice=ll[1:-1]
In [756]: llslice[1][1:2]=[10,11,12]
In [757]: ll
Out[757]: [1, 2, [3, 10, 11, 12, 5], 6]
修改切片内的项目会修改原始列表中的相同项目。与numpy
相反,列表切片是副本。但这是一个浅薄的副本。您必须付出额外的努力来制作深层副本(import copy
)。
/usr/lib/python3/dist-packages/numpy/lib/index_tricks.py
包含一些索引函数,旨在使某些索引操作更方便。实际上有几个是使用自定义__getitem__
方法的类或类实例。它们也可以作为如何自定义切片和索引的模型。