@flori65817: Du solltest Schritt für Schritt vorgehen. Solange das laden aus der Datei nicht klappt, brauchst Du die Funktion zum Sortieren ja gar nicht erst anfangen, denn dann hast Du ja noch gar nichts zum Sortieren. Streng genommen kann man zum Testen vom Sortieren natürlich auch Daten per Code zusammenbasteln, aber dann braucht man die Funktion zum Laden nicht vorher schreiben. Der Punkt ist, wenn Du beide Funktionen geschrieben hast und beide so gar nicht funktionieren, hast Du etwas bei der Entwicklung falsch gemacht. Man schreibt nicht mehrere Funktionen von denen man weiss das sie nicht funktionieren, sondern fängt die nächste immer erst an wenn die davor auch wirklich funktioniert.
Was Du generell auch benötigst, sowohl für das Programm als auch für die Entwicklung, wäre eine Funktion die eine verkettete Autoliste ausgibt. Um das Ergebnis auszugeben, und auch um Zwischenschritte zu überprüfen. Also beispielsweise um die Daten nach dem Laden mal auszugeben, um zu testen ob das laden in eine verkettete Liste überhaupt korrekt funktioniert hat.
Und dann sind Namen wichtig. Das ist nichts was man nachträglich vielleicht mal überdenkt, nein, gute, passende, und vor allem korrekte Namen sind schon während der Entwicklung wichtig. Namen sind keine Kosmetik. Wenn man nämlich Probleme hat für etwas einen passenden Namen zu finden, dann deutet das in der Regel auf Probleme hin. Zum Beispiel das man Werte zu einem Objekt zusammenfasst die gar nicht zusammengehören, oder das man das Problem noch nicht richtig verstanden hat, oder die Lösung nicht richtig verstanden hat. Namen wie `f` und `fNeu` sind keine guten Namen. Und `zahlen` ist *richtig* schlecht, weil so richtig falsch, denn der Iterator liefert gar keine Zahlen.
`pruefvar` sagt nichts darüber aus was mit dieser Variable geprüft wird.
Es sind überflüssige Kommentare im Code. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht dort ja bereits als Code, sondern warum der das so macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in der Regel auch alles was in der Dokumentation von Programmiersprache und verwendeten Bibliotheken steht, denn das muss man im eigenen Programm ja nicht noch mal (ab)schreiben.
Kommentare vor einer Funktion oder Methode die beschreiben was die Funktion/Methode macht, gehören da nicht hin sondern als Docstring zu der Funktion/Methode. Natürlich nur wenn sie nicht trivial und offensichtlich und damit überflüssig sind.
Weder `Dateneinlesen()` noch `sortierung()` gehören in die Klasse, denn das sind keine Operationen auf einem einzelnen `Fahrzeug`. Beide verwendet das Objekt auf dem sie aufgerufen wurden ja auch gar nicht. `Dateneinlesen()` bekommt das noch nicht einmal als Argument und `sortierung()` verwendet das `self`-Argument nicht.
`Dateneinlesen()` hält sich von der Schreibweise nicht mal an die unpythonische camelCase-Schreibweise. Das wäre dann `datenEinlesen()`. Daten ist ziemlich allgemein, da werden Fahrzeuge gelesen. Das kann man ruhig im Namen erwähnen, denn dann enthält der mehr Information für den Leser.
Funktions und Methodennamen beschreiben üblicherweise die Tätigkeit die sie durchführen. `sortierung()` ist keine Tätigkeit, das wäre `sortieren()`.
Richtig wäre es die Hinweise umzusetzen die hier gegeben wurden und erst einmal den ersten grösseren Schritt zu implementieren: Das laden der Fahrzeuge aus der Datei. Dazu wäre es nützlich die auch ausgeben zu können um das laden zu überprüfen, also brauchst Du vorher/gleichzeitig eine Funktion, welche eine gegebene Fahrzeugliste ausgibt.
Wenn ich das implementieren müsste, ohne die Einschränkungen einer Hausaufgabe, würde ich die externen Module `attr` und `prettyprinter` verwenden um zumindest bei der Entwicklung eine gute, eindeutige Ausgabe der verketteten Liste zu bekommen ohne die selber programmieren zu müssen. Teilausschnitt einer solchen Lösung:
Code: Alles auswählen
#!/usr/bin/env python3
from attr import attrib, attrs
from prettyprinter import cpprint, install_extras
install_extras(["attrs"])
@attrs
class Fahrzeug:
marke = attrib()
farbe = attrib()
vorgaenger = attrib(default=None)
nachfolger = attrib(default=None)
def hat_vorgaenger(self):
return bool(self.vorgaenger)
def hat_nachfolger(self):
return bool(self.nachfolger)
def anhaengen(self, fahrzeug):
fahrzeug.vorgaenger = self
self.nachfolger = fahrzeug
...
def lade_fahrzeuge(dateiname):
...
...
def main():
print("Lade Fahrzeuge...")
fahrzeuge = lade_fahrzeuge("test.txt")
cpprint(fahrzeuge)
...
if __name__ == "__main__":
main()
Du müsstest hier das `cpprint()` durch eine eigene Funktion zur Ausgabe der Fahrzeuge ersetzen. Und beim Laden der Fahrzeuge aus der Datei solltest Du auch eine Datei berücksichtigen die keine Daten enthält, also überlegen was `lade_fahrzeuge()` in dem Fall machen soll. Zwei sinnvolle Alternativen wären: a) Ausnahme auslösen oder b) `None` zurück geben. Und falls man `None` zurück gibt, sollte auch der restliche Code von der Annahme ausgehen, dass eine leere (verkettete) Autoliste durch diesen Wert repräsentiert wird.
Wenn man `lade_fahrzeuge()` implementiert, dann bekomme ich für die Beispieldaten diese Ausgabe:
Code: Alles auswählen
Lade Fahrzeuge...
Fahrzeug(
marke='BMW',
farbe='rot',
nachfolger=Fahrzeug(
marke='VW',
farbe='blau',
vorgaenger=<Recursion on Fahrzeug with id=140331913104408>,
nachfolger=Fahrzeug(
marke='Toyota',
farbe='gruen',
vorgaenger=<Recursion on Fahrzeug with id=140331913007288>,
nachfolger=Fahrzeug(
marke='Honda',
farbe='tuerkis',
vorgaenger=<Recursion on Fahrzeug with id=140331913010816>,
nachfolger=Fahrzeug(
marke='VW',
farbe='schwarz',
vorgaenger=<Recursion on Fahrzeug with id=140331913010368>,
nachfolger=Fahrzeug(
marke='Subaru',
farbe='braun',
vorgaenger=<Recursion on Fahrzeug with id=140331913009304>,
nachfolger=Fahrzeug(
marke='BMW',
farbe='blau',
vorgaenger=<Recursion on Fahrzeug with id=140331913007848>
)
)
)
)
)
)
)