您好我正在尝试从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功能?
欢呼声, 大卫
答案 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)