5

您好我正在尝试从 ndarray 派生一个类。我坚持使用文档__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 函数吗?

干杯,大卫

4

3 回答 3

8

有人可以向我解释为什么以及如何实现 getitem 函数吗?

对于您当前的代码,__getitem__不需要 a 。SelObj当我删除实现时,您的类工作正常( undefined 除外) __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])
于 2013-10-10T20:06:59.927 回答
4

问题在这里:

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)
于 2013-10-10T20:06:36.160 回答
0

我不明白你为什么要从np.ndarraytype 继承一个类。您可以使用标准 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)
于 2021-02-11T05:55:27.157 回答