问题描述
在我的上一个问题中,我学会了适当调整子类的大小.整洁的.不幸的是,当我要调整大小的数组是计算结果时,这种方法不再起作用:
In my previous question, I learned to resize a subclassed ndarray
in place. Neat. Unfortunately, that no longer works when the array that I am trying to resize is the result of a computation:
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)
确切的输出(包括回溯)是:
The exact output (including traceback) is:
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
我认为这是因为numpy
创建了一个新的ndarray
并将其传递给__array_prepare__
.不过,在此过程中的某个时刻,似乎是"output
"数组获取视听为我的Foo
类型,尽管在这一点上文档似乎还不是100%清晰/准确.无论如何,在进行视图强制转换后,输出不再拥有数据,因此无法就位重塑(据我所知).
I think this is because numpy
creates a new ndarray
and passes it to __array_prepare__
. At some point along the way though, it seems that the "output
"array gets view-casted to my Foo
type, although the docs don't seem to be 100% clear/accurate on this point. In any event, after the view casting, the output no longer owns the data making it impossible to reshape in place (as far as I can tell).
是否可以通过某种numpy伏都教(__array_prepare__
,__array__
)等方式将数据所有权转移到我的子类实例中?
Is there any way, via some sort of numpy voodoo (__array_prepare__
, __array__
) etc. to transfer ownership of the data to the instance of my subclass?
推荐答案
这不是一个令人满意的答案,但是它也不适合用作注释...您可以使用ufunc来解决数据的拥有问题. out
参数.一个愚蠢的例子:
It is hardly a satisfactory answer, but it doesn't fit into a comment either... You can work around the owning of the data by using the ufunc's out
parameter. A silly example:
>>> 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
我认为上面的输出与c[:] = a + b
一致,因为它拥有数据,但以将其从临时数组复制到c
中为代价.但是,当您使用out
参数时,应该不会发生这种情况.
I think that the output above is consistent with c[:] = a + b
getting to own the data at the expense of copying it into c
from a temporary array. But that shouldn't be happening when you use the out
parameter.
由于您已经担心数学表达式中的中间存储,因此微管理如何处理它可能不是一件坏事.也就是说,替换
Since you were already worried about intermediate storage in your mathematical expressions, it may not be such a bad thing to micro-manage how it is handled. That is, replacing
g = a + b + np.sqrt(d*d + e*e + f*f)
使用
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
可以为您节省一些中间存储器,并且它可以让您拥有自己的数据.它确实将可读性计数"的口号抛到了窗外,但是...
may save you some intermediate memory, and it lets you own your data. It does throw the "readability counts" mantra out the window, but...
这篇关于转让numpy数据的所有权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!