当对ndarray进行子类化时,为什么转置发生在__array_finitize__之后而不是之前



为了简单起见,让我们从numpy文档中复制诊断ndarray子类:

import numpy as np
class MySubClass(np.ndarray):
def __new__(cls, input_array, info=None):
obj = np.asarray(input_array).view(cls)
obj.info = info
return obj
def __array_finalize__(self, obj):
print('In __array_finalize__:')
print('   self is %s' % repr(self))
print('   obj is %s' % repr(obj))
if obj is None: return
self.info = getattr(obj, 'info', None)

现在让我们做一个简单的例子:

>>> x = MySubClass(np.ones((1,5)))
In __array_finalize__:
self is MySubClass([[1., 1., 1., 1., 1.]])
obj is array([[1., 1., 1., 1., 1.]])
>>> y = x.T
In __array_finalize__:
self is MySubClass([[1., 1., 1., 1., 1.]])
obj is MySubClass([[1., 1., 1., 1., 1.]])

正如我们所看到的,转置被传递给__array_finalize__。除了将"敲定"一词的含义延伸到全新的领域之外,这种行为的目的是什么?

发送实际输出,即通过这个钩子进行转置,以使其最终确定,这不是更有意义吗?

用我的子类可能需要的任何后处理来修改基转置,推荐的方法是什么?

这是因为为了创建新对象,它们依赖于已经可用的(通用(函数PyArray_NewFromDescrAndBase来处理内存分配。PyArray_Transpose的源代码显示,首先从现有阵列中创建具有相似形状和步长的新对象,然后通过访问先前分配的内存来校正这些对象:

/*
* this allocates memory for dimensions and strides (but fills them
* incorrectly), sets up descr, and points data at PyArray_DATA(ap).
*/
Py_INCREF(PyArray_DESCR(ap));
ret = (PyArrayObject *) PyArray_NewFromDescrAndBase(
Py_TYPE(ap), PyArray_DESCR(ap),
n, PyArray_DIMS(ap), NULL, PyArray_DATA(ap),
flags, (PyObject *)ap, (PyObject *)ap);
if (ret == NULL) {
return NULL;
}
/* fix the dimensions and strides of the return-array */
for (i = 0; i < n; i++) {
PyArray_DIMS(ret)[i] = PyArray_DIMS(ap)[permutation[i]];
PyArray_STRIDES(ret)[i] = PyArray_STRIDES(ap)[permutation[i]];
}

这里PyArray_NewFromDescrAndBase负责调用__array_finalize__,因此该方法接收具有不正确形状和步幅(即非转置(的版本。可以采取不同的做法,但PyArray_NewFromDescrAndBase需要一个额外的参数来推迟对__array_finalize__的调用,然后可以在调整形状和步幅后手动进行。

最新更新