7

リストを保持する 2 つのプロパティがあります。このリストのアイテムが変更されるたびに、他のリストが更新されるようにしたいと思います。これにはステートメントが含まれますobj.myProp[3]=5。現在、このステートメントは getter 関数を呼び出してリスト全体を取得し、リストから 3 番目の項目を取得して、それを 5 に設定します。myPropリストは変更されますが、2 番目のリストは更新されません。

class Grid(object):

    def __init__(self,width=0,height=0):

        # Make self._rows a multi dimensional array
        # with it's size width * height
        self._rows=[[None] * height for i in xrange(width)]
        # Make `self._columns` a multi dimensional array
        # with it's size height * width
        self._columns=[[None] * width for i in xrange(height)]

    @property
    def rows(self):
        # Getting the rows of the array
        return self._rows

    @rows.setter
    def rows(self, value):
        # When the rows are changed, the columns are updated
        self._rows=value
        self._columns=self._flip(value)

    @property
    def columns(self):
        # Getting the columns of the array
        return self._columns

    @columns.setter
    def columns(self, value):
        # When the columns are changed, the rows are updated
        self._columns = value
        self._rows = self._flip(value)

    @staticmethod
    def _flip(args):
        # This flips the array
        ans=[[None] * len(args) for i in xrange(len(args[0]))]
        for x in range(len(args)):
            for y in range(len(args[0])):
                ans[y][x] = args[x][y]
        return ans

実行例:

>>> foo=grid(3,2)
>>> foo.rows
[[None, None], [None, None], [None, None]]
>>> foo.columns
[[None, None, None], [None, None, None]]
>>> foo.rows=[[1,2,3],[10,20,30]]
>>> foo.rows
[[1, 2, 3], [10, 20, 30]]
>>> foo.columns
[[1, 10], [2, 20], [3, 30]]
>>> foo.rows[0][0]=3
>>> foo.rows
[[3, 2, 3], [10, 20, 30]]
>>> foo.columns
[[1, 10], [2, 20], [3, 30]]

最後の 3 行を見ると、ここで実際の問題が発生しています。サブリストの最初の項目を 3 に設定しましたが、foo.columns自分自身を更新して 3 をリストに入れることはありません。

要するに、サブアイテムが変更されている場合でも、常に別の変数を更新する変数を作成するにはどうすればよいですか?

私はPython 2.7を使用しています

4

3 に答える 3

7

あなたの問題は、問題のある行に設定していないことです-それを 取得してから、そのメンバーの1つを変更しています。これはセッターを起動しません。あなたが提案しているAPIでは、ゲッターとセッターもアタッチされたリストを返す必要があります。foo.rows

行と列のプロパティを使用してエントリを設定するのではなく、次の__getitem__ようなメソッドを追加することをお勧めします。

class Grid(object):

    def __init__(self, width=0, height=0):
        self._data = [None] * width * height;
        self.width = width
        self.height = height

    def __getitem__(self, pos):
        if type(pos) != tuple or len(pos) != 2:
            raise IndexError('Index must be a tuple of length 2')
        x, y = pos
        if 0 <= x < self.width and 0 <= y < self.height:
            return self._data[x + self.width * y]
        else:
            raise IndexError('Grid index out of range')

    def __setitem__(self, pos, value):
        if type(pos) != tuple or len(pos) != 2:
            raise IndexError('Index must be a tuple of length 2')
        x, y = pos
        if 0 <= x < self.width and 0 <= y < self.height:
            self._data[x + self.width * y] = value
        else:
            raise IndexError('Grid index out of range')

    @property
    def columns(self):
        return [
            [self[x, y] for x in xrange(self.width)]
            for y in xrange(self.height)
        ]

    @property
    def rows(self):
        return [
            [self[x, y] for y in xrange(self.height)]
            for x in xrange(self.width)
        ]

破線は次のようになります。

foo[0, 0] = 3
于 2012-05-19T16:17:37.903 に答える
3

rowsまたはリストを返すだけcolumnsでは、アイテムが変更されたときに何が起こるかを制御することはできません。

1つの可能性は、リストを直接取得/設定するためのプロパティを提供するのではなく、位置x/yのアイテムにセッター/ゲッターを提供することです。

良いバージョンは、__setitem__/を持ち、タプルを受け入れるようにすることです。そうすれば、とを使用し__getitem__て要素にアクセスできます。foo[x,y]foo[x,y] = bar

もう1つの方法は、要素が変更されたことを検出するリストのラッパーを返すことですが、ネストされたリストごとにそれを行う必要があります。

于 2012-05-19T16:01:39.937 に答える
-1

numpyの使用を検討することをお勧めします。特に、transposeメソッドは、軸が転置された基になる行列の「ビュー」を提供します。つまり、一方を変更すると、もう一方も変更されます。

それがあなたのニーズに合わない場合、私が見ることができる唯一の方法は、「rows」および「columns」メソッドを定義して、実際にはデータを保存しないカスタム「ビューオブジェクト」を返すことです。 、しかしそれはグリッドオブジェクト自体のいくつかのプライベート(共有)データを指しています。これらはリストのようにすることができますが、一部の操作 (追加やクリアなど) をサポートしません。

于 2012-05-19T16:56:06.037 に答える