在我之前的问题中,我学会了调整子类的大小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__)等将数据的所有权转移到我的子类的实例?
这不是一个令人满意的答案,但它也不适合评论......您可以使用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)
可以节省一些中间内存,它可以让你拥有自己的数据.它确实抛出了"可读性计数"的口号,但......
| 归档时间: |
|
| 查看次数: |
2031 次 |
| 最近记录: |