转移numpy数据的所有权

mgi*_*son 10 python numpy

在我之前的问题中,我学会了调整子类的大小ndarray.整齐.不幸的是,当我尝试调整大小的数组是计算的结果时,它不再有效:

import numpy as np

class Foo(np.ndarray):
    def __new__(cls,shape,dtype=np.float32,buffer=None,offset=0,
                strides=None,order=None):
        return np.ndarray.__new__(cls,shape,dtype,buffer,offset,strides,order)

    def __array_prepare__(self,output,context):
        print output.flags['OWNDATA'],"PREPARE",type(output)
        return np.ndarray.__array_prepare__(self,output,context)

    def __array_wrap__(self,output,context=None):
        print output.flags['OWNDATA'],"WRAP",type(output)

        return np.ndarray.__array_wrap__(self,output,context)

a = Foo((32,))
#resizing a is no problem
a.resize((24,),refcheck=False)

b = Foo((32,))
c = Foo((32,))

d = b+c
#Cannot resize `d`
d.resize((24,),refcheck=False)
Run Code Online (Sandbox Code Playgroud)

确切的输出(包括追溯)是:

True PREPARE <type 'numpy.ndarray'>
False WRAP <class '__main__.Foo'>
Traceback (most recent call last):
  File "test.py", line 26, in <module>
    d.resize((24,),refcheck=False)
ValueError: cannot resize this array: it does not own its data
Run Code Online (Sandbox Code Playgroud)

我认为这是因为numpy创建了一个新的ndarray并传递给它__array_prepare__.在某些方面,似乎" output"数组被视图转换为我的Foo类型,尽管在这一点上文档似乎不是100%清晰/准确.无论如何,在视图转换之后,输出不再拥有数据,因此无法重新定位(据我所知).

有没有办法,通过某种numpy voodoo(__array_prepare__,__array__)等将数据的所有权转移到我的子类的实例?

Jai*_*ime 6

这不是一个令人满意的答案,但它也不适合评论......您可以使用ufunc的out参数解决数据的拥有问题.一个愚蠢的例子:

>>> a = Foo((5,))
>>> b = Foo((5,))
>>> c = a + b # BAD
True PREPARE <type 'numpy.ndarray'>
False WRAP <class '__main__.Foo'>
>>> c.flags.owndata
False

>>> c = Foo((5,))
>>> c[:] = a + b # BETTER
True PREPARE <type 'numpy.ndarray'>
False WRAP <class '__main__.Foo'>
>>> c.flags.owndata
True

>>> np.add(a, b, out=c) # BEST
True PREPARE <class '__main__.Foo'>
True WRAP <class '__main__.Foo'>
Foo([  1.37754085e-38,   1.68450356e-20,   6.91042737e-37,
         1.74735556e-04,   1.48018885e+29], dtype=float32)
>>> c.flags.owndata
True
Run Code Online (Sandbox Code Playgroud)

我认为上面的输出与c[:] = a + b获取数据是一致的,代价是c从临时数组中复制数据.但是,当您使用out参数时,不应该发生这种情况.

由于您已经担心数学表达式中的中间存储,因此微观管理它的处理方式可能并不是一件坏事.也就是说,替换

g = a + b + np.sqrt(d*d + e*e + f*f)
Run Code Online (Sandbox Code Playgroud)

g = foo_like(d) # you'll need to write this function!
np.multiply(d, d, out=g)
g += e * e
g += f * f
np.sqrt(g, out=g)
g += b
g += a
Run Code Online (Sandbox Code Playgroud)

可以节省一些中间内存,它可以让你拥有自己的数据.它确实抛出了"可读性计数"的口号,但......