Hallo!
Da ich kein Informatiker bin (d.h. ich es nicht gelernt habe) und es von Programmiersprache zu Programmiersprache unterschiedliche Ansätze gibt, wollte ich mal wieder eine prinzipielle Frage stellen.
Folgende Situation als einfachstes Beispiel:
Es gibt 3 Instanzen A, B und C von selbst definierten Klassen.
Dabei hält A eine Referenz auf B und B eine Referenz auf C
Frage: ist es nun "schlechter Programmierstil", wenn A eine Methode von C direkt aufruft, weil bei guter Programmierung B die Vermittlerrolle spielen und die Nachricht an C delegieren sollte?
Das wäre doch zumindest für spätere Änderungen hilfreich, da man Referenzen über mehrere Instanzen sehr schlecht verfolgen kann.
Ich würde gern wissen, wie das in Pythonkreisen gesehen wird.
Gruß,
der Michel
Zugriff über mehrere Instanzen = guter Stil?
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Generell gilt, dass man das so weit wie möglich vermeiden sollte, aber ich finde, eine Indirektion ist derweilen vertretbar. Man vergleiche und bilde sich selbst eine Meinung:
vs.
Stefan
Code: Alles auswählen
fleet.ships.append(ship)
Code: Alles auswählen
fleet.append_ship(ship)
... aber aus,
welches man noch weg lassen könnte, wird schnell
etc. pp. und dann ist guter Rat teuer, wenn sich die Zugriffe auf
das Attribut ships häufen und man es änder muß.
HTH
Gerald
Code: Alles auswählen
def addShip( self, someShip ):
self.ships.append( someShip )
Code: Alles auswählen
def addShip( self, myNewShip ):
self.ships.append( myNewShip )
myNewShip.shipyard = self
myNewShip.owner = self.owner
das Attribut ships häufen und man es änder muß.
HTH
Gerald
Auf der anderen Seite:sma hat geschrieben:Generell gilt, dass man das so weit wie möglich vermeiden sollte, aber ich finde, eine Indirektion ist derweilen vertretbar. Man vergleiche und bilde sich selbst eine Meinung:
vs.Code: Alles auswählen
fleet.ships.append(ship)
StefanCode: Alles auswählen
fleet.append_ship(ship)
Code: Alles auswählen
fleet.ship.captain.name
Code: Alles auswählen
fleet.ship.name
Code: Alles auswählen
fleet.name
Ob es tatsächlich generelle Meinung ist, dass man Indirektionen vermeiden sollte, bezweifele ich mal. Große Frameworks nutzen viel Indirektion, man muss sich nur mal die TextDocument-API von Qt4 anschauen. Ich persönlich finde das nicht schlecht oder "evil", solange es im Rahmen bleibt und vor allem lesbar und logisch ist.
Da nach "pythonisch" gefragt wurde: Ich würde sagen das Gesetz von Demeter wird in der englischsprachigen Newsgroup relativ oft erwähnt und die Bibliotheken sind in der Regel auch nicht so entworfen, dass man viele Punktoperatoren hintereinander anwenden kann. Im Gegensatz zu Sprachen wie Smalltalk oder Io, wo die APIs so einen Stil fördern.
Bei ``fleet.ships.append(ship)`` wird ein wenig wissen über die internen Strukturen vom `fleet`-Exemplar preisgegeben, denn `append()` suggeriert, dass die Schiffe irgendwie linear geordnet verwaltet werden. Das muss ja eigentlich nicht sein. Wenn man irgendwann auf die Idee kommt, dass ein Schiff nicht mehrmals in der Flotte sein kann und `fleet.ships` mit einem `set` realisiert, bekommt man Probleme, wenn Code von aussen direkt auf das `ships`-Attribut zugreift, denn `set.append()` gibt's nicht.
@Gromit: Die Änderung lässt sich aber noch mit Properties umsetzen, ohne das der Client-Code etwas davon merkt.
@lunar: Die Qt4-API lässt sich nicht als Begründung für "pythonisch" oder nicht heranziehen, da es im Kern eine C++-API ist.
Bei ``fleet.ships.append(ship)`` wird ein wenig wissen über die internen Strukturen vom `fleet`-Exemplar preisgegeben, denn `append()` suggeriert, dass die Schiffe irgendwie linear geordnet verwaltet werden. Das muss ja eigentlich nicht sein. Wenn man irgendwann auf die Idee kommt, dass ein Schiff nicht mehrmals in der Flotte sein kann und `fleet.ships` mit einem `set` realisiert, bekommt man Probleme, wenn Code von aussen direkt auf das `ships`-Attribut zugreift, denn `set.append()` gibt's nicht.
@Gromit: Die Änderung lässt sich aber noch mit Properties umsetzen, ohne das der Client-Code etwas davon merkt.
@lunar: Die Qt4-API lässt sich nicht als Begründung für "pythonisch" oder nicht heranziehen, da es im Kern eine C++-API ist.
Ach? Na, mich würde ja mal interessieren, wie du eine solche API dann "pythonisch" entwirfst ... abgesehen davon, dass man Indirektionen überhaupt nicht vermeiden kann, wenn mehrere gleichnamige Attribute auf verschiedenen Ebenen existieren. Und ob es jetzt pythonisch ist, alle Bestandteile einer API wie der QTextDocument-API in eine einzige Klasse zu packen, sei mal dahingestellt ...BlackJack hat geschrieben:@lunar: Die Qt4-API lässt sich nicht als Begründung für "pythonisch" oder nicht heranziehen, da es im Kern eine C++-API ist.
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Hi Lunar!
Ich kann Blackjacks Argumente gut nachvollziehen, vor allem das Problem der nachträglichen Änderungen und ja, ich fragte nach pythonisch.
Wenn man gut gepflegte Klassen- und Beziehungsdiagramme hat, dann kann man ja vielleicht noch nachvollziehen, welche Instanzen (evtl. aus anderen Modulen) auf ein Attribut zugreifen und evtl. anzupassen sind. Wenn man aber nur Code hat, ist man schon fast verloren.
also:
Ob das schön ist, sei dahingestellt, aber es ist möglich.
Problem ist nur (wenn man die Zahl der erreichbaren Attribute nicht stark einschränkt), dass diese Methoden kaskadierend implementiert werden müssen, was zu rapide wachenden Klassen führt.
Gruß,
der Michel
Ich kann Blackjacks Argumente gut nachvollziehen, vor allem das Problem der nachträglichen Änderungen und ja, ich fragte nach pythonisch.
Wenn man gut gepflegte Klassen- und Beziehungsdiagramme hat, dann kann man ja vielleicht noch nachvollziehen, welche Instanzen (evtl. aus anderen Modulen) auf ein Attribut zugreifen und evtl. anzupassen sind. Wenn man aber nur Code hat, ist man schon fast verloren.
Ich gehe davon aus, dass Blackjack zwischen API unterscheidet, die zum einen mit der C++-API "verwandt" sind und jenen, die von Grund auf nur für ein Python-Modul konzipiert sind und die pythonischen Grundsätze beim Design respektieren.lunar hat geschrieben:Ach? Na, mich würde ja mal interessieren, wie du eine solche API dann "pythonisch" entwirfst ...BlackJack hat geschrieben:@lunar: Die Qt4-API lässt sich nicht als Begründung für "pythonisch" oder nicht heranziehen, da es im Kern eine C++-API ist.
Da bin ich anderer Meinung. Denn C wird ja direkt nur von B referenziert und hat erstmal nichts mit A zutun. Wenn A also ein Attribut von C haben möchte, dann kann B durch seine Implementierung bestimmen, ob es das preisgeben möchte.lunar hat geschrieben: abgesehen davon, dass man Indirektionen überhaupt nicht vermeiden kann, wenn mehrere gleichnamige Attribute auf verschiedenen Ebenen existieren.
also:
Code: Alles auswählen
fleet.get_ship_name(ship_id)
fleet.get_crewmember_name(ship_id, crewmember_id)
Problem ist nur (wenn man die Zahl der erreichbaren Attribute nicht stark einschränkt), dass diese Methoden kaskadierend implementiert werden müssen, was zu rapide wachenden Klassen führt.
Gruß,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Nachtrag:
Bei Verwendung von Methoden der Instanz A um auf Attribute von B und C zuzugreifen, kann man eine weitere große Stärke von Python hervorragend ausspielen: die Verwendung von mapping/filtering und diversen iterierbaren Objekten (für die Argumente).
Michel
Bei Verwendung von Methoden der Instanz A um auf Attribute von B und C zuzugreifen, kann man eine weitere große Stärke von Python hervorragend ausspielen: die Verwendung von mapping/filtering und diversen iterierbaren Objekten (für die Argumente).
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...