2012-05-19 3 views
5

passieren Ich habe eine Eigenschaft, die zwei Listen enthält. Wenn sich ein Element in dieser Liste ändert, möchte ich, dass sich die andere Liste selbst aktualisiert. Dazu gehört die Anweisung obj.myProp [3] = 5. Im Moment ruft diese Anweisung die Getter-Funktion auf, um die gesamte Liste abzurufen, ruft das dritte Element aus der Liste ab und setzt das auf 5. Die myProp-Liste wird geändert, aber die zweite Liste wird nie aktualisiert.Python: wie eine Eigenschaft und mit einer Setter-Funktion, die alle Änderungen, die mit dem Wert

hier ist mein Code

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 

und hier ist ein Beispiel laufen.

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

Wenn Sie die letzten drei Zeilen betrachten, tritt hier das eigentliche Problem auf. Ich setze das erste Element der Unterliste auf drei, aber foo.columns aktualisiert sich nie selbst, um die 3 in seine Liste aufzunehmen.

Kurz gesagt, wie mache ich eine Variable, die immer eine andere Variable aktualisiert, auch wenn der Unterpunkt geändert wird.

Ich verwende Python 2.7

Antwort

5

Ihr Problem ist, dass Siefoo.rows auf der Codezeile nicht Einstellung sind - sind Sie es bekommen, und dann eines seiner Mitglieder zu ändern. Dadurch wird der Setter nicht ausgelöst. Mit der von Ihnen vorgeschlagenen API müssten Sie eine Liste zurückgeben, die auch Getter und Setter enthält.

Sie würden besser nicht die Zeilen und Spalten-Eigenschaften verwenden, um Einträge zu setzen, und fügen Sie eine __getiten__ Methode wie folgt:

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

Die gestrichelte Linie wird dann:

foo[0, 0] = 3 
2

wenn Sie einfach Ihre rows oder columns Liste zurück, dann werden Sie nie über jede Kontrolle haben, was passiert, wenn ein Element geändert wird.

Eine Möglichkeit wäre, keine Eigenschaften zum direkten Abrufen/Festlegen der Listen bereitzustellen, sondern Setter/Getter für ein Element an Position x/y bereitzustellen.

wäre eine schöne Version __setitem__/__getitem__ und haben sie ein Tupel akzeptieren, dass die Art und Weise Sie die Elemente acces konnte mit foo[x,y] und foo[x,y] = bar haben sein.

ein anderer Weg wäre, einen Wrapper um die Liste herumzugeben, der erkennt, ob ein Element geändert wurde, aber dann müssen Sie das auch für jede verschachtelte Liste tun.

0

I empfehlen, dass Sie sich mit numpy befassen. Insbesondere bietet die Methode transpose eine "Ansicht" der zugrunde liegenden Matrix mit den transponierten Achsen, das heißt, wenn Sie eine ändern, ändert sich die andere.

Wenn das nicht Ihren Anforderungen entspricht, dann ist die einzige Möglichkeit, die API zu sehen, die Sie arbeiten möchten, die Methoden "rows" und "columns" zu definieren, um benutzerdefinierte "view objects" zurückzugeben speichert die Daten tatsächlich, aber diese verweisen zurück auf einige private (gemeinsam genutzte) Daten im Grid-Objekt selbst. Diese könnten listenartig sein, würden jedoch einige Operationen nicht unterstützen (z. B. anhängen oder löschen).

Verwandte Themen