(numpy)__array_wrap__做什么?

sun*_*nny 5 python numpy

我是第一次进入SciPy LinAlg模块,并且看到了以下功能:

def _makearray(a):
    new = asarray(a)
    wrap = getattr(a, "__array_prepare__", new.__array_wrap__)
    return new, wrap
Run Code Online (Sandbox Code Playgroud)

到底是__array_wrap__做什么的?我找到了文档,但是我不明白这个解释:

 At the end of every ufunc, this method is called on the input object with the
 highest array priority, or the output object if one was specified. The ufunc-
 computed array is passed in and whatever is returned is passed to the user. 
 Subclasses inherit a default implementation of this method, which transforms the
 array into a new instance of the object’s class. Subclasses may opt to use this
 method to transform the output array into an instance of the subclass and update
 metadata before returning the array to the user.
Run Code Online (Sandbox Code Playgroud)

这是否仅仅意味着它将任何函数的输出转换回a,array因为它可能会分解为其他元素进行逐元素处理?相关地,不管解释如何,将其wrap作为对象意味着什么?你会怎么做?

我正在查看numpy.linalg.inv... 的代码...包装在这里做什么?

    **a, wrap = _makearray(a)**
    _assertRankAtLeast2(a)
    _assertNdSquareness(a)
    t, result_t = _commonType(a)

    if a.shape[-1] == 0:
        # The inner array is 0x0, the ufunc cannot handle this case
        **return wrap(empty_like(a, dtype=result_t))**

    signature = 'D->D' if isComplexType(t) else 'd->d'
    extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
    ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
    return wrap(ainv.astype(result_t))
Run Code Online (Sandbox Code Playgroud)

hpa*_*ulj 5

np.ma.masked_array.__array_wrap__是更新元数据 (the mask)的数组子类的示例。

File:        /usr/lib/python3/dist-packages/numpy/ma/core.py
Definition:  np.ma.masked_array.__array_wrap__(self, obj, context=None)
Source:
    def __array_wrap__(self, obj, context=None):
        """
        Special hook for ufuncs.
        Wraps the numpy array and sets the mask according to context.
        """
Run Code Online (Sandbox Code Playgroud)

np.matrix.__array_wrap__似乎继承了ndarray版本。我猜这是因为matrix,虽然是一个子类,但没有需要更新的元数据。

通常,带有hook,的想法是它是一个在正常处理中被深入调用的函数。默认方法可能不会做任何事情。但这是子类可以采取特殊行动的一种方式。类开发人员编写这样的钩子,这样类用户就不必担心这些细节。有了__...__名字,它就不是公共接口的一部分——尽管 Python 让我们在幕后达到顶峰。

的一个例子wrapping,即返回与输入具有相同类的数组是:

In [659]: np.cumsum(np.arange(10))
Out[659]: array([ 0,  1,  3,  6, 10, 15, 21, 28, 36, 45], dtype=int32)

In [660]: np.cumsum(np.matrix(np.arange(10)))
Out[660]: matrix([[ 0,  1,  3,  6, 10, 15, 21, 28, 36, 45]], dtype=int32

In [665]: np.cumsum(np.ma.masked_array(np.arange(10)))
Out[665]: 
masked_array(data = [ 0  1  3  6 10 15 21 28 36 45],
             mask = False,
       fill_value = 999999)
Run Code Online (Sandbox Code Playgroud)

返回值都相同,但数组子类会有所不同,具体取决于输入类。


cumsum可能不是最好的例子。cumsum掩码数组有自己的 版本,将掩码值视为0

In [679]: m=np.ma.masked_array(np.arange(10),np.arange(10)%2)

In [680]: m
Out[680]: 
masked_array(data = [0 -- 2 -- 4 -- 6 -- 8 --],
             mask = [False  True False  True False  True False  True False  True],
       fill_value = 999999)

In [681]: np.cumsum(m)
Out[681]: 
masked_array(data = [0 -- 2 -- 6 -- 12 -- 20 --],
             mask = [False  True False  True False  True False  True False  True],
       fill_value = 999999)
Run Code Online (Sandbox Code Playgroud)

add.accumulate类似于cumsum,但没有特殊的屏蔽版本:

In [682]: np.add.accumulate(np.arange(10))
Out[682]: array([ 0,  1,  3,  6, 10, 15, 21, 28, 36, 45], dtype=int32)

In [683]: np.add.accumulate(m)
Out[683]: 
masked_array(data = [ 0  1  3  6 10 15 21 28 36 45],
             mask = False,
       fill_value = 999999)
Run Code Online (Sandbox Code Playgroud)

最后一个是掩码数组,但掩码是默认值False,掩码值包含在总和中。