2012-05-19 6 views
5

Mam dwie właściwości, które przechowują listy. ilekroć jakikolwiek element na tej liście ulegnie zmianie, chciałbym aby druga lista aktualizowała się sama. dotyczy to również instrukcji obj.myProp [3] = 5. teraz, ta instrukcja wywołuje funkcję getter, aby pobrać całą listę, pobiera trzeci element z listy i ustawia go na 5. lista myProp zmienia się, ale druga lista nigdy nie jest aktualizowana.python: jak mieć właściwość i funkcję ustawiającą, która wykrywa wszystkie zmiany, które mają wartość

tutaj jest mój kod

class grid(object): 

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

     #make self._rows a multi demensional array 
     #with it's size width*height 
     self._rows=[ [None]*height for i in xrange(width) ] 
     #make self._columns a multi demensional 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 collumns 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 

i tutaj jest przykładem 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]] 

jeśli spojrzysz na ostatnie trzy linie, to tutaj pojawia się rzeczywisty problem. Ustawiłem pierwszy element podlisty na trzy, ale foo.columns nigdy się nie aktualizuje, aby umieścić 3 na liście.

Krótko mówiąc, w jaki sposób utworzyć zmienną, która zawsze aktualizuje inną zmienną, nawet w przypadku zmiany podelementu.

Używam Pythona 2.7

Odpowiedz

5

Twoim problemem jest to, że nie jesteś ustawieniefoo.rows na linii naruszającego - jesteś coraz go, a następnie zmodyfikowanie jednego z jego członków. To nie wystrzeli ustawiającego. Proponując interfejs API, musisz zwrócić listę, do której dołączono również moduły pobierające i ustawiające.

Zrobiłbyś lepiej nie korzystać z wierszy i kolumn właściwości ustawić wpisy i dodać __getiten__ metody takie jak to:

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

Linia przerywana wówczas postać:

foo[0, 0] = 3 
2

jeśli po prostu wrócić listę rows lub columns, to nigdy nie ma żadnej kontroli, co dzieje się, gdy element zostanie zmieniona.

Jedną z możliwości nie jest zapewnienie właściwości do bezpośredniego uzyskania/ustawienia list, ale zapewnienie ustawiaczy/elementów pobierających dla pozycji na pozycji x/y.

miłym wersja byłoby mieć __setitem__/__getitem__ i je akceptuje krotki, w ten sposób można Acces elementy używając foo[x,y] i foo[x,y] = bar.

Innym sposobem jest zwrócenie opakowania wokół listy, które wykryje, że element został zmieniony, ale musisz to zrobić również dla każdej listy zagnieżdżonej.

0

I zalecamy zapoznać się z użyciem numpy. W szczególności metoda transpose daje "widok" podstawowej matrycy z przeniesionymi osiami, co oznacza, że ​​jeśli ją zmienisz, druga zmieni się.

Jeśli to nie odpowiada Twoim potrzebom, jedyny sposób, w jaki mogę zobaczyć, że API, które chcesz pracować, to zdefiniowanie metod "wierszy" i "kolumn" w celu zwrócenia niestandardowych "obiektów widoku", które nie faktycznie przechowują dane, ale to wskazuje na niektóre prywatne (współdzielone) dane w samym obiekcie siatki. Mogą to być listy podobne, ale nie obsługują niektórych operacji (na przykład dodania lub wyczyszczenia).

Powiązane problemy