爲了在寫入時實現複製,我們需要修改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 #copy
print a, b
b[2] = 200 #no copy
print a, b
c = a[::2].view(cowarray)
c[0] = 1000 #copy
print a, c
d = a.view(cowarray)
np.sin(d, d) #copy
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 ]
我已經用這種方法,除了它總是隻讀的,如果調用者想要它讀寫,他們可以自己複製它。 – coderforlife