python: how to have a property and with a setter function that detects all changes that happen to the value

properties, python

Solution

Your problem is that you're not setting `foo.rows` on the offending line - you're getting it, and then modifying one of it's members. This isn't going to fire the setter. With the API you're proposing, you would need to return a list that has getters and setters attached as well.

You'd do better to not use the rows and columns properties to set entries, and add a `__getitem__` method like this:

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

The broken line then becomes:

foo[0, 0] = 3

Problem

I have a two properties which holds lists. Whenever any item in this list changes, I would like the other list to update itself. This includes the statement `obj.myProp[3]=5`. Right now, this statement calls the getter function to get the whole list, gets the third item from the list, and sets that to 5. the `myProp` list is changed, but the second list never gets updated. ``` 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 ``` Example run: ``` >>> 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]] ``` If you look at the last three lines, this is where the actual problem occurs. I set the first item of the sublist to three, but `foo.columns` never updates itself to put the 3 in its list. So in short, how do I make a variable that always updates another variable, even when it's subitem is being changed? I'm using Python 2.7

Original source