从ndarray继承称为__getitem__

时间:2013-10-10 20:02:15

标签: python numpy

您好我正在尝试从ndarray派生一个类。我坚持docs中找到的食谱,但是当我使用 getiem ()函数时,我得到一个我不明白的错误。我确定这是应该如何工作但我不明白如何正确地做到这一点。基本上添加“dshape”属性的我的类看起来像:

class Darray(np.ndarray):
    def __new__(cls, input_array, dshape, *args, **kwargs):
        obj = np.asarray(input_array).view(cls)
        obj.SelObj = SelObj
        obj.dshape = dshape
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.info = getattr(obj, 'dshape', 'N')  

    def __getitem__(self, index):        
        return self[index]

当我现在尝试做的时候:

D = Darray( ones((10,10)), ("T","N"))

解释器将以最大深度递归失败,因为他一遍又一遍地调用 getitem

有人可以向我解释为什么以及如何实现getitem功能?

欢呼声, 大卫

3 个答案:

答案 0 :(得分:7)

  

有人可以向我解释为什么以及如何实现getitem功能?

对于您当前的代码,不需要__getitem__。当我删除SelObj实现时,您的类正常工作(未定义的__getitem__除外)。

最大递归深度错误的原因是__getitem__的定义,它使用self[index]self.__getitem__(index)的简写符号。如果必须覆盖__getitem__,请确保调用__getitem__的超类实现:

def __getitem__(self, index):
    return super(Darray, self).__getitem__(index)

至于你为什么这样做:有很多理由来覆盖这个功能,例如:您可以将名称与数组的行相关联:

class NamedRows(np.ndarray):
    def __new__(cls, rows, *args, **kwargs):
        obj = np.asarray(*args, **kwargs).view(cls)
        obj.__row_name_idx = dict((n, i) for i, n in enumerate(rows))
        return obj

    def __getitem__(self, idx):
        if isinstance(idx, basestring):
            idx = self.__row_name_idx[idx]
        return super(NamedRows, self).__getitem__(idx)

演示:

>>> a = NamedRows(["foo", "bar"], [[1,2,3], [4,5,6]])
>>> a["foo"]
NamedRows([1, 2, 3])

答案 1 :(得分:3)

问题在于:

def __getitem__(self, index):        
    return self[index]

foo[index]只需致电foo.__getitem__(index)。但在您的情况下,只返回foo[index],只调用foo.__getitem__(index)。在无限循环中重复,直到用完堆栈空间。

如果您想要遵循父类,则必须执行此操作:

def __getitem__(self, index):        
    return super(Darray, self)[index]

......或者,可能更明确地说:

def __getitem__(self, index):        
    return super(Darray, self).__getitem__(index)

答案 2 :(得分:0)

我不明白你为什么要从 np.ndarray 类型继承一个类。您可以使用标准的 OOP 方法实现与上述相同的想法。以下示例与您的代码执行相同的操作,但更优雅。而不是子类化,我只是将 numpy 数组视为我的特殊对象的成员,该对象也包含 dshape。它只是创建 __getitem__()__setitem__(),使其行为与我们为 np.ndarray 对象添加下标一样。

class Darray:
    def __init__(self, input_array, dshape):
        self.array = np.array(input_array)
        self.dshape = dshape

    def __getitem__(self, item):
        return self.array[item]

    def __setitem__(self, item, val):
        self.array[item] = val

现在您可以编写更多方法来描述您想要的确切行为。无论 dhape 应该对继承的数组做什么,现在都要对 self.array 成员做。

这种方法的额外好处是没有令人头疼的递归深度、__array_finalize__super() 或在这个子类化和重载过程中可能出现的任何其他陷阱。对于预期用例,总有一种更简单的方法。

编辑:在我上面的示例中,__getitem__ 方法不适用于 , 维数组的 N 分隔索引。对此进行修复,

    def __getitem__(self, *args):
        return self.array.__getitem__(*args)