@vlancer: Vorweg ein Fehler den Du ziemlich häufig machst: ``is`` ist nicht zum Vergleichen von beliebigen Werten da. Das Dein Programm überhaupt funktioniert ist im Grunde Zufall. ``is`` testet ob zwei Objekte identisch sind, nicht ob sie den gleichen Wert haben. Man sollte das nur verwenden, wenn man auch ganz sicher ist, dass man auf Objektidentität testen möchte. Im Regelfall ist das nur bei `None` der Fall, weil die Sprachspezifikation garantiert, dass das ein Singleton ist -- es also nur *ein* Exemplar davon geben kann. Bei Wahrheitswerten ist es durchaus möglich, dass es mehr als ein wahres Objekt vom Typ `bool` geben kann. Die wären dann zwar gleich, aber eben nicht identisch.
Explizite Vergleiche mit `True` oder `False` sind aber auch mit ``==`` oder ``!=`` unschön, weil unnötig. Wenn man einen Wahrheitswert `x` hat, dann ergibt ``x == True`` wieder einen Wahrheitswert -- nämlich den *gleichen* den man schon an `x` gebunden hat. Wenn man das Gegenteil feststellen möchte, dann ist ``not x`` einem ``x == False`` oder gar ``x != True`` vorzuziehen.
Anstelle ein `Stroke`-Exemplar als Elternobject in einer `Connection` zu setzen, könntest Du die `Connection`-Exemplare auch mit `next`- und `previous`-Attributen versehen, die jeweils auf den Vorgänger und den Nachfolger verweisen oder auf `None`, falls es ein Endpunkt von einem `Stroke` ist. Das ist sicher effizienter als die aktuelle Position immer mit `index()` zu suchen. Dann braucht man auch die `get*Connection()`-Methoden nicht mehr.
`Connection._parent` sollte `Connection.parent` heissen und die `getParent()`- und `setParent()`-Methoden sind dann überflüssig. Triviale Getter/Setter braucht man in Python nicht -- die Schreibarbeit kann man sich sparen.
`Connection.angle()` könnte man zu einem Property machen. So als Übung. Oder umbenennen, so dass es nicht nach einem Attributnamen klingt.
Damit die `get*Connection()`-Methoden so funktionieren, müsste `Stroke` noch mindestens `__getitem__()` implementieren. Und solltest Du bei dem Weg über ein Elternobjekt bleiben, lassen sich die beiden Methoden auch viel kürzer schreiben. Beispielhaft und ungetestet für `getPreviousConnection()`:
Code: Alles auswählen
def getPreviousConnection(self):
i = self.parent.index(self) - 1
return self.parent[i] if 0 <= i < len(self.parent) else None
Es würde vielleicht Sinn machen auf `Node`-Objekten mehr Operationen zu implementieren. Zum Beispiel um solche Punkte zu addieren oder subtrahieren, oder den Winkel einer Geraden zwischen zwei `Node`\s zu berechnen. Dann würde `Connection.angle()` zum Beispiel zu ``return self.start.angle_to(self.end)`` werden.
`Connection.draw()` ist ziemlich lang. Da könnte man vielleicht ein paar Zeilen kompakter ausdrücken und Funktionen heraus ziehen. Die Bedingung ob Rundungen invloviert ist, lässt sich zum Beispiel unter die 80-Zeichen-Grenze bringen:
Code: Alles auswählen
if any(x in self.name for x in ['rb', 'lb', 'rt', 'lt']):
Und `inwards` kann man einsparen. Immer wenn man einen Wahrheitswert aufgrund einer Bedingung setzt, braucht man kein ``if``/``else`` denn die Bedingung *selbst* wird ja zu einem einen Wahrheitswert ausgewertet. `inwards` liesse sich also auch so zuweisen:
Code: Alles auswählen
inwards = (
(
'lt' in self.name
and self.start.x >= self.end.x
and self.start.y >= self.end.y
) or (
'rt' in self.name
and self.start.x <= self.end.x
and self.start.y >= self.end.y
) or (
'lb' in self.name
and self.start.x >= self.end.x
and self.start.y <= self.end.y
) or (
'rb' in self.name
and self.start.x <= self.end.x
and self.start.y <= self.end.y
)
)
Und da es nur einmal benötigt wird, könnte man es auch gleich als ``if``-Bedingung verwenden.
Warum wird in `Stroke.index()` die Ausnahme durch einen "Fehlerwert" ersetzt? Ausnahmen wurden ja gerade erfunden um solche speziellen Werte für Fehler loszuwerden. Du tauscht hier auch nur eine Ausnahme gegen eine andere ein, nämlich an der Stelle wo Du dann versuchst mit dem `None` etwas zu machen was damit nicht geht. Zum Beispiel 1 addieren oder abziehen.