通过python对象设置全局numpy数组的子部分或切片

时间:2012-02-20 02:35:00

标签: python arrays class numpy

我试图通过对象属性引用一个“全局”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]

1 个答案:

答案 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.xn.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.我知道这些都不是完美的,但也许这里的其他人会想出更好的方法。对不起,我做不了更多。