我试图通过对象属性引用一个“全局”numpy数组的片段。这就是我认为类结构会是这样的,它是用例。
import numpy
class X:
def __init__(self, parent):
self.parent = parent
self.pid = [0, 1, 2]
def __getattr__(self, name):
if name == 'values':
return self.parent.P[self.pid]
else:
raise AttributeError
class Node:
def __init__(self):
self.P = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
self._values = X(self)
def __getattr__(self, name):
if name == 'x':
return self._values.values
else:
raise AttributeError
以下是用例:
>>> n = Node()
>>> print n.P
[ 1 2 3 4 5 6 7 8 9 10]
>>> print n.x
[1 2 3]
>>> print n.x[1:3]
[2 3]
哪种方法正常,现在我想通过n.P
属性为n.x
分配值,
>>> n.x = numpy.array([11, 12, 13])
得到,
>>> print n.P
[ 11 12 13 4 5 6 7 8 9 10]
或者通过
为切片指定值>>> n.x[1:3] = numpy.array([77, 88])
得到,
>>> print n.P
[ 11 77 88 4 5 6 7 8 9 10]
但是对于我的生活,我正在努力让这项任务奏效。我认为使用__setattr__
和__setitem__
会很容易,但是整整一天后我仍然无法管理它。
最终,n.x
将作为多维数组返回,其中X
类将重新整形,但存储在n.P
中,这是一个向量。我删除了这个以简化问题。
我希望得到一些帮助。有没有人这样做过?或者建议怎么做?
提前感谢您的帮助。
解
所以经过多天的磕磕绊绊之后,我找到了一个解决方案。我怀疑这可以简化和改进。解决方案是在Node对象中创建一个X对象。当它被检索时,它返回临时numpy对象(Values),知道它的父节点和pids。 setslice _函数在此更新中定义了具有新值的全局P数组。如果指定了X对象,则它不会返回Values对象,而是直接设置全局P值。
两点,可能无效:1。Node和X对象必须是 object 的子类; 2.如果设置更高维度的数组,则需要使用__setitem__
代替,这不适用于1D数组或列表。
正如我所说,我怀疑这段代码可以改进,因为我不确定我是否完全理解它。我很乐意接受改进和建议。
感谢您的帮助,尤其是Bago。
这是我的最终代码。
import numpy
class Values(numpy.ndarray):
def __new__(cls, input_array, node, pids):
obj = numpy.asarray(input_array).view(cls)
obj.node = node
obj.pids = pids
return obj
def __setslice__(self, i, j, values):
self.node._set_values(self.pids[i:j], values)
class X(object):
def __get__(self, instance, owner):
p = instance.P[instance.pids]
return Values(p, instance, instance.pids)
def __set__(self, instance, values):
instance.P[instance.pids] = values
class Node(object):
x = X()
def __init__(self, pids=[0, 1, 2]):
self.P = numpy.arange(11)
self.pids = pids
def _set_values(self, pids, values):
self.P[pids] = values
node = Node(pids=[4, 5, 6, 7])
print '\nInitial State:'
print 'P =', node.P
print 'x =', node.x
print 'x[1:3] =', node.x[1:3]
print '\nSetting node.x = [44, 55, 66, 77]:'
node.x = [44, 55, 66, 77]
print 'P =', node.P
print 'x =', node.x
print 'x[1:3] =', node.x[1:3]
print '\nSetting node.x[1:3] = [100, 200]:'
node.x[1:3] = [100, 200]
print 'P =', node.P
print 'x =', node.x
print 'x[1:3] =', node.x[1:3]
答案 0 :(得分:0)
我不清楚什么不起作用,但我想也许你正在尝试做这样的事情:
import numpy
class X(object):
def __init__(self, parent):
self.parent = parent
self.pid = [0, 1, 2]
@property
def values(self):
tmp = self.parent.P[self.pid]
return tmp
@values.setter
def values(self, input):
self.parent.P[self.pid] = input
class Node(object):
def __init__(self):
self.P = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
self._values = X(self)
@property
def x(self):
return self._values.values
@x.setter
def x(self, input):
self._values.values = input
我希望你能开始。
更新
使用此方法n.x[1:3] = [77, 88]
不起作用的原因是n.x
和n.x[:] = ~
都调用返回tmp
的X.values的get方法。但tmp
是P的一部分的副本,而n.x[:] = ~
tmp
被丢弃后P
未更新。 tmp
是一个副本,因为当您使用另一个数组索引数组时,您获得的副本不是视图。下面是一个更清晰的示例,您可以阅读有关numpy切片/索引here的更多信息。
>>> P = np.arange(10)
>>> pid = np.array([1, 2, 3])
>>> Q = P[pid]
>>> Q[:] = 99
>>> P
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> R = P[1:4]
>>> R[:] = 99
>>> P
array([ 0, 99, 99, 99, 4, 5, 6, 7, 8, 9])
>>> P[[1,2]][:] = 88
>>> P
array([ 0, 99, 99, 99, 4, 5, 6, 7, 8, 9])
setitem无济于事,因为您正在调用tmp
而不是X
的setitem方法。
使其工作的最简单方法是用切片替换pid数组,但我知道这是一种限制。您还可以跟踪tmp
数组,拥有self._tmp,以便稍后可以将值从_tmp移动到P.我知道这些都不是完美的,但也许这里的其他人会想出更好的方法。对不起,我做不了更多。