为了实现写时复制,我们需要修改ndarray对象的
base
、
data
和
strides
。我认为这不能在纯Python代码中完成。我使用了一些Cython代码来修改这些属性。
以下是IPython笔记本中的代码:
%load_ext cythonmagic
使用Cython定义copy_view()
:
%%cython
cimport numpy as np
np.import_array()
np.import_ufunc()
def copy_view(np.ndarray a):
cdef np.ndarray b
cdef object base
cdef int i
base = np.get_array_base(a)
if base is None or isinstance(base, a.__class__):
return a
else:
print "copy"
b = a.copy()
np.set_array_base(a, b)
a.data = b.data
for i in range(b.ndim):
a.strides[i] = b.strides[i]
定义一个ndarray的子类:
class cowarray(np.ndarray):
def __setitem__(self, key, value):
copy_view(self)
np.ndarray.__setitem__(self, key, value)
def __array_prepare__(self, array, context=None):
if self is array:
copy_view(self)
return array
def __array__(self):
copy_view(self)
return self
一些测试:
a = np.array([1.0, 2, 3, 4])
b = a.view(cowarray)
b[1] = 100
print a, b
b[2] = 200
print a, b
c = a[::2].view(cowarray)
c[0] = 1000
print a, c
d = a.view(cowarray)
np.sin(d, d)
print a, d
输出结果:
copy
[ 1. 2. 3. 4.] [ 1. 100. 3. 4.]
[ 1. 2. 3. 4.] [ 1. 100. 200. 4.]
copy
[ 1. 2. 3. 4.] [ 1000. 3.]
copy
[ 1. 2. 3. 4.] [ 0.84147098 0.90929743 0.14112001 -0.7568025 ]