2012-02-20 6 views
3

オブジェクト属性を介して「グローバル」numpy配列のスライスを参照しようとしています。ここで私はクラスの構造は、それがユースケースのようになると思います。今、私が取得するグローバルnumpy配列のサブセクションまたはスライスをpythonオブジェクトを介して設定する

>>> n.x = numpy.array([11, 12, 13]) 

、によってn.x属性を通じてn.Pに値を代入したい、正常に動作します

>>> 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] 

:ここ

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 

は、ユースケースです

>>> 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が返されますが、ベクトルであるn.Pに格納されます。問題を単純化するためにこれを削除しました。

私はこれについていくつかの助けが好きです。誰もこれを前にしたことがありますか?またはこれを行う方法を提案しますか?

ご協力いただきありがとうございます。

SOLUTION

だから私の周りにつまずきの多くの日は、解決策を見つけた後。私は、これを簡素化して洗練させることができると思う。解決策は、NodeオブジェクトにXオブジェクトを作成することです。それが取得されると、親ノードとpidを知っている一時numpyオブジェクト(Values)を返します。 setslice _関数は、グローバルP配列を新しい値で更新する際に定義されています。 Xオブジェクトが割り当てられている場合、Valuesオブジェクトは返されませんが、グローバルP値は直接設定されます。

無効である可能性がある2つのポイント:1.ノードおよびXオブジェクトはオブジェクトのサブクラスでなければなりません。 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

それは働いていないものを私に明確ではないのですが、私は多分あなたはこのような何かをしようとしていると思う:

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 

私はそれはあなたが始めたのget願っています。 n.xn.x[:] = ~は両方tmpを返しX.valuesのgetメソッドを呼び出すためn.x[1:3] = [77, 88]は、このアプローチを使用して動作しないことを

更新

理由があります。しかしtmpはPの一部のコピーであり、n.x[:] = ~の後にtmpが破棄され、Pは更新されません。 tmpはコピーです。なぜなら、別の配列で配列にインデックスを付けると、ビューではなくコピーが得られるからです。ここでは、より明確にするための例を示します。numpyのスライス/インデックスの詳細については、hereを参照してください。あなたがtmpないXのSetItem関数メソッドを呼び出しているので

>>> 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関数は、助けにはなりません。

pid配列をスライスに置き換えるのが最も簡単な方法ですが、これは制限があります。配列tmpを追跡し、self._tmpを持って、_tmpからPに値を後で移動することもできます。私はそれらのどちらも完璧ではないことを知っていますが、おそらく他の誰かがより良いアプローチを考え出すでしょう。すみません、私はもっとはできませんでした。

+0

ありがとうございます。それは主に動作しますが、nx [1:3] = numpy.array([77、88])は実行できず、nP = numpy.array([1、77、88、4、5、6、7、8、9 、10])。私はどこでも@ values.setitemデコレータを見てきましたが、運はありません。 – duane

+0

バゴありがとうございます。私もそう思っていました。私はコピーの代わりにスライスのポインタを渡す方法を探し始めました。私の最初の実装は、後でPに手動で関数を実行することで追加したXに値を格納することでしたが、私はそれをやめたいと思っています。その間に関数を使用してスライスを更新しなければならない場合があります。つまり、n.set_values(スライス、値)です。私はsetitemとsetattrを検出し、関数呼び出しとしてXの値を検出する追加のダミーオブジェクトについて考えています。それがうまくいくかどうかわからない、私はそれの周りに私の頭をかなり得ることはできません。とにかくありがとう。 – duane

関連する問題