Python numpy数组子类上操作的不需要的包装结果

Python numpy数组子类上操作的不需要的包装结果,python,numpy,Python,Numpy,我正试图了解这本书的细节,但它很难理解。(第二种可能性:我很笨。) 下面是一个简单的例子: import numpy as np class MyArray(np.ndarray): def __new__(cls, input_array, foo='foo'): self = input_array.view(cls) self.foo = foo return self def __array_finalize__(sel

我正试图了解这本书的细节,但它很难理解。(第二种可能性:我很笨。)

下面是一个简单的例子:

import numpy as np

class MyArray(np.ndarray):
    def __new__(cls, input_array, foo='foo'):
        self = input_array.view(cls)
        self.foo = foo
        return self

    def __array_finalize__(self, from_array):
        if from_array is not None:
            self.foo = getattr(from_array, 'foo', 'foo')
下面是不想要的行为的演示:

>>> a = MyArray(np.arange(9).reshape(3,3))
>>> a
MyArray([[0, 1, 2],
         [3, 4, 5],
         [6, 7, 8]])
>>> 
>>> a.foo
'foo'
>>> a.sum()
MyArray(36)
>>> np.sum(a)
MyArray(36)
>>> print(a.sum())
36 # interesting
>>> a.sum().shape
()

如何防止应该返回单个数字的函数或方法将结果包装在
MyArray
中?

我不是类专家,但使用以下代码:

编辑:在进一步查看上面提到的页面并播放更多内容后,我想到:

import numpy as np

class RealisticFooArray(np.ndarray):

    def __new__(cls, input_array, foo='Foo'):
        # Input array is an already formed ndarray instance
        # We first cast to be our class type
        obj = np.asarray(input_array).view(cls)
        # add the new attribute to the created instance
        obj.foo = foo
        # Finally, we must return the newly created object:
        return obj

    def __array_finalize__(self, obj):
        # see InfoArray.__array_finalize__ for comments
        if obj is None: return
        self.foo = getattr(obj, 'foo', None)

arr = np.arange(9)
fa = RealisticFooArray(arr).reshape(3,3)
print(fa)
print(fa.foo)
print(fa.sum())
print(type(fa))

Edit2:array最后一行的更正\u finalize

很好的问题,我将尝试回答,尽管我不能100%确定该解决方案是否有副作用


您必须指定
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法。通过在中更改代码,我获得了期望的结果(我相信这些结果是:没有将标量结果包装为MyArray,对吗?)

导致:

>>> a = MyArray(np.arange(9).reshape(3,3))
>>> a
MyArray([[0, 1, 2],
         [3, 4, 5],
         [6, 7, 8]])
>>> 
>>> a.foo
'foo'
>>> a.sum()
36
>>> np.sum(a)
36
>>> print(a.sum())
36 
>>> a.sum().shape
()

这很难。我能想到的只有两个解决方案,我不喜欢其中任何一个——一个来自numpy文档中关于子类化ndarray的内容——使用array_wrap。第二个是更多的save->覆盖np.sum和其他您想要的函数

注意:

下面的代码需要润色,主要是带有数组的解决方案。然而,看起来,array_wrap是正确的方向,因为它也适用于其他函数(*.mean()等),但正如您所说,文档非常密集,很难说破解这些神奇函数会产生什么后果。 另一方面,重写是简单明了的,但是谁想重写所有现有函数呢

import numpy as np

class MyArray(np.ndarray):
    def __new__(cls, input_array, foo='foo'):
        self = input_array.view(cls)
        self.foo = foo
        return self

    # First solution - define this func that is magically called on results (check documentation)
    def __array_wrap__(self, out_arr, context=None):
       if not out_arr.shape:
           out_arr = out_arr.reshape(-1)[0] 
           # Check more on documentation. This is just example
           # It definitely needs more polishing

           return out_arr
       else:
           # This part was there before. That means it needs to be used, but thats up to you. It seems it simply passes result to __array_finalize__
           return super(MyArray, self).__array_wrap__(out_arr,self, context)

    def __array_finalize__(self, from_array):

        if from_array is not None:
            self.foo = getattr(from_array, 'foo', 'foo')

    # Use only if you know what you are doing
    ## This is second solution. Override. Check result, act accordingly
    #def sum(self,*args,**kwargs):
    #    result = super().sum()
    #    if not result.shape:
    #        return result.reshape(-1)[0] 
    #    else:
    #        return result

a = MyArray(np.arange(9).reshape(3,3))

print(a.foo)
print(a.sum())
print(a.mean().__class__)
print(a.sum().__class__)
print(np.mean(a).__class__)

>>> foo
>>> 36
>>> <class 'numpy.float64'>
>>> <class 'numpy.int64'>
>>> <class 'numpy.float64'>
将numpy导入为np
类MyArray(np.ndarray):
定义新的(cls,输入数组,foo='foo'):
self=输入\数组视图(cls)
self.foo=foo
回归自我
#第一个解决方案-定义此函数,该函数在结果上被神奇地调用(查看文档)
定义数组换行(self,out\u arr,context=None):
如果没有超出外形:
out\u arr=out\u arr.重塑(-1)[0]
#查看更多文档。这只是一个例子
#它肯定需要更多的抛光
返回
其他:
#这部分以前就在那里。这意味着它需要被使用,但这取决于你。它似乎只是将结果传递给_数组_finalize__
返回super(MyArray,self)。\uuuuu数组\uu换行\uuuu(out\u arr,self,context)
def_u_数组_ufinalize__(自,自数组):
如果from_数组不是None:
self.foo=getattr(来自_数组'foo','foo')
#只有当你知道自己在做什么时才使用
##这是第二个解决方案。推翻检查结果,采取相应行动
#定义和(自身,*args,**kwargs):
#结果=super().sum()
#如果不是result.shape:
#返回结果。重塑(-1)[0]
#其他:
#返回结果
a=MyArray(np.arange(9).重塑(3,3))
印刷品(a.foo)
打印(a.sum())
打印(a.平均值()。\uuuuu类\uuuuuuu)
打印(a.sum()。\uuuuu类\uuuuuuuu)
印刷品(np.平均值(a).\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu类)
>>>福
>>> 36
>>> 
>>> 
>>> 

不幸的是,
FooArray
无法通过
FooArray(np.arange(9)。重塑(3,3))
进行初始化。是的,我更喜欢这种实例化方法。我打赌有办法,但我还没挖到足够深的地方去找到它。我只是编辑了我的解决方案。这是你正在寻找的更多…和另一个编辑。我忘了检查foo属性是否正常工作,但我知道它不正常。现在可以了,谢谢
RealisticFooArray
也有同样的问题<代码>RealisticFooArray(np.array([1,2,3])).sum()->
RealisticFooArray(6)
。当您使用
print
时,您看不到这一点。“我相信这是:没有将标量结果包装为MyArray,对吗?”很高兴它能工作。我同意这是很多代码。。。我将尝试将其压缩一点并在此处更新。如果您选择在列或行上应用求和,此解决方案已经中断:a.sum(axis=0)或a.sum(axis=1)返回36,而不是所需的结果。@b3rt0您是否投票让我得到50?不如先把问题记下来,投我一票?我把它修好了,它不再坏了。在发布答案之前,检查一下简单的案例。你的解决方案有一个重大缺陷。因此我投了反对票。我对答案投了反对票,得到-2,但我认为这不是一个正确的答案。但是如果-1对你如此重要,我就撤销它。
>>> a = MyArray(np.arange(9).reshape(3,3))
>>> a
MyArray([[0, 1, 2],
         [3, 4, 5],
         [6, 7, 8]])
>>> 
>>> a.foo
'foo'
>>> a.sum()
36
>>> np.sum(a)
36
>>> print(a.sum())
36 
>>> a.sum().shape
()
import numpy as np

class MyArray(np.ndarray):
    def __new__(cls, input_array, foo='foo'):
        self = input_array.view(cls)
        self.foo = foo
        return self

    # First solution - define this func that is magically called on results (check documentation)
    def __array_wrap__(self, out_arr, context=None):
       if not out_arr.shape:
           out_arr = out_arr.reshape(-1)[0] 
           # Check more on documentation. This is just example
           # It definitely needs more polishing

           return out_arr
       else:
           # This part was there before. That means it needs to be used, but thats up to you. It seems it simply passes result to __array_finalize__
           return super(MyArray, self).__array_wrap__(out_arr,self, context)

    def __array_finalize__(self, from_array):

        if from_array is not None:
            self.foo = getattr(from_array, 'foo', 'foo')

    # Use only if you know what you are doing
    ## This is second solution. Override. Check result, act accordingly
    #def sum(self,*args,**kwargs):
    #    result = super().sum()
    #    if not result.shape:
    #        return result.reshape(-1)[0] 
    #    else:
    #        return result

a = MyArray(np.arange(9).reshape(3,3))

print(a.foo)
print(a.sum())
print(a.mean().__class__)
print(a.sum().__class__)
print(np.mean(a).__class__)

>>> foo
>>> 36
>>> <class 'numpy.float64'>
>>> <class 'numpy.int64'>
>>> <class 'numpy.float64'>