假设我有一个简单的Test
类,它继承自numpy.ndarray
(documentation on ndarray
subclassing)。此类创建一个对象,该对象是另一个ndarray
的局部视图。现在我想创建一个可以就地修改此视图的方法。类似的东西:
import numpy
class Test(numpy.ndarray):
def __new__(cls, info='Test class'):
base = numpy.ndarray.__new__(cls, (6, 2), dtype=float)
view = base[0:2, :]
view.info = info
return view
def __array_finalize__(self, obj):
if obj is None:
return
self.info = getattr(obj, 'info', None)
def change_view(self, start, stop):
"""This is the method I'd like to implement"""
# Incorrect, but represents what I am looking for
self = self.base[start:stop]
if __name__ == '__main__':
t = Test()
print(t)
print(t.info)
t.change_view(1, 5)
print(t)
print(t.info)
我希望方法.change_view(x)
修改.base
属性的视图以显示行[1:5]
而不是[0:2]
,这是__new__()
中的默认值}。
这可能吗?如果是这样,怎么样?否则,为什么不呢?请注意,.base
永远不会更改(它总是占用相同的内存空间),我只想更改它的视图。
change_view()
中的评论。我知道self = self.base[start:stop]
不正确,我知道并理解为什么,但我认为这是一种表达我所寻找内容的简短方法。self[:] = ...
或self.data = ...
。但是,在更改视图大小时这将不起作用(情况确实如此)。这个问题was already asked here(或者至少是类似的情况),但答案提到了返回修改后的数组的解决方案(即没有就地修改)或者使用了包装器对象(即具有属性)使用要修改的数组。)
我知道这些可能性,我知道它们可以更简单甚至更方便。但是,我想了解为什么(如果是这样的话)不可能做我正在寻找的事情。
答案 0 :(得分:2)
1)您无法更改ndarray实例或子类实例指向的就地数据。抱歉!事实证明,有可能更改ndarray实例指向的数据,但这是一个可怕的想法,希望很快就会删除:-)。见https://github.com/numpy/numpy/issues/7093
2)您尝试分配给self
这样只会改变方法本地绑定中self
变量的绑定,我担心这表明对Python的方式有一个相当基本的误解执行和对象模型工作。我只是提出这个问题,因为成功继承ndarray
hard 。 真的很难。探究不可能。 (例如,受欢迎的pandas
库的开发人员放弃了。)尽管该文档给出了误导性的印象,但numpy并不是真正设计用于支持子类化,并且它不能很好地工作。我通常建议没有人试图继承ndarray
;如果你还不是一个专业的Python程序员,那么这个问题要好十倍。可能我们会删除那个愚蠢的页面并完全禁用子类,除了它会破坏向后兼容性:-(。我建议找一个不同的策略来解决你的问题。
答案 1 :(得分:1)
编写
之类的代码时var = value
它为var
分配新值并删除旧值,但这仅在当前范围内为真,并且前一个值var
的所有其他别名保持不变。 Python的self
并不特别,它只是一个变量,所以当你写的时候
self = self.base[start:stop]
您只需将self.base[start:stop]
的值分配给局部变量self
,但self
中预先包含的值不会更改以及所有其他值的引用(这是一个实例你要改变的Test类)。您可以使用change_view
的以下实现来测试它:
def change_view(self, start, stop):
"""This is the method I'd like to implement"""
# Incorrect, but represents what I am looking for
print('before assignment')
print(self)
self = self.base[start:stop]
print('after assignment')
print(self)
print('end change_view')
我认为使用此实现运行代码应该清除一些东西。 可能的实现可能与此类似:
def change_view(self, start, stop):
"""This is the method I'd like to implement"""
# Incorrect, but represents what I am looking for
self[:] = self.base[start:stop]
重要的区别在于它改变了变量self
中包含的值,而不是为变量赋值。我认为这样的事情应该适用于python列表,但numpy.ndarray
更复杂。此外,由于它在C
中实施,它可能根本不可能。例如,您需要以某种方式调整视图大小,但是您无法使用numpy.ndarray.resize
,因为视图不拥有它的数据;简单地指定size
和shape
也不会起作用。