====== LU01.L11 - Spaghetticode entwirren ====== ===== 1. Analyse des Ausgangscodes ===== ^ Zeile / Konstrukt ^ Grundstruktur ^ Bemerkung ^ | ''i = 0'', ''fertig = False'', ''total = 0'' | Sequenz | Drei Zustandsvariablen, die von Hand gepflegt werden müssen. | | ''while not fertig'' | Iteration | Endlosschleife mit Abbruchflagge statt echter Laufbedingung. | | ''%%if i >= len(bestellungen)%%'' | Selektion | Wird nur gebraucht, weil die Schleife nicht über die Elemente läuft. | | ''%%if b["status"] == "storniert"%%'' und ''%%if b["menge"] <= 0%%'' | Selektion | Sachlich sinnvoll, aber unnötig verschachtelt. | | ''continue'' | **keine der drei** | Imitiert einen Sprung an den Schleifenanfang – genau das, was die strukturierte Programmierung vermeiden will. | | ''i = i + 1'' an drei Stellen | Sequenz | Klassische Fehlerquelle: Eine vergessene Stelle erzeugt eine Endlosschleife. | | ''fertig = True'' | Sequenz | Flaggenvariable als Ersatz für eine Schleifenbedingung. | ===== 2. Musterlösung ===== ~~NOCACHE~~ === main.py === {{gh>https://github.com/templates-python/m323-lu01-a11-umsatz-refactoring/blob/solution/main.py}} Übrig bleiben genau die drei Grundstrukturen: Sequenz (Initialisierung und Rückgabe), Iteration (''for''), Selektion (''if''). ===== 3. Was durch den Umbau verschwunden ist ===== * **Der Index ''i''.** Damit auch jede Möglichkeit, ihn falsch zu initialisieren, an einer Stelle nicht hochzuzählen (Endlosschleife!) oder um eins danebenzuliegen. * **Die Flagge ''fertig''.** Die ''for''-Schleife kennt ihr Ende selbst. * **Die Sprünge.** Ohne ''continue'' liest sich der Ablauf von oben nach unten. * **Zwei Verschachtelungsebenen.** Die beiden Bedingungen sind zu einer benannten Frage zusammengefasst, die man laut vorlesen kann: //Wenn die Bestellung verrechenbar ist, zähle sie dazu.// ===== 4. Wie geprüft wird ===== Die Gleichwertigkeit prüft ''test_umsatz_wie_referenz'' gegen ''umsatz_alt'' aus ''referenz.py'' – über vier Datensätze, inklusive leerer Liste, komplett stornierter Liste und ungültiger Mengen. Die //Struktur// lässt sich mit einem gewöhnlichen Test nicht messen: Beide Fassungen liefern 362.70. Darum lesen zwei Tests die Datei ''main.py'' als Syntaxbaum ein: === main_test.py === {{gh>https://github.com/templates-python/m323-lu01-a11-umsatz-refactoring/blob/solution/main_test.py}} ''test_iteration_ohne_while'' verlangt eine ''for''-Schleife und verbietet ''while'', ''test_keine_spruenge'' verbietet ''continue'' und ''break''. Beide prüfen zusätzlich das korrekte Ergebnis – sonst wären sie mit einer leeren Datei erfüllbar. Eine Abgabe, die richtig rechnet, aber die alte Struktur behält, kommt damit auf 9 von 11 Testpunkten. ===== 5. Antworten auf die Zusatzfragen ===== ==== Frage 1: Vergessenes Hochzählen ==== Entfernt man beispielsweise das ''i = i + 1'' im Storno-Zweig, bleibt die Schleife für immer bei derselben stornierten Bestellung stehen – eine **Endlosschleife**. Das Programm hängt ohne Fehlermeldung. In der neuen Fassung ist dieser Fehler gar nicht mehr möglich, weil die Iteration nicht mehr von Hand gesteuert wird. ==== Frage 2: Böhm und Jacopini ==== Der Ausgangscode brauchte scheinbar Sprünge (''continue''), um einen Fall zu überspringen. Die neue Fassung zeigt: Dieselbe Wirkung entsteht durch **Selektion** – statt zu überspringen, wird nur im passenden Fall etwas getan. Das ist genau die Aussage des Theorems: Jeder berechenbare Algorithmus lässt sich allein mit Sequenz, Selektion und Iteration ausdrücken. Sprünge sind bequem, aber nie zwingend nötig. ==== Frage 3: Deklarative Formulierung ==== //Der Umsatz ist die Summe aus Menge mal Preis über alle nicht stornierten Bestellungen mit positiver Menge.// In Python direkt so ausdrückbar: def umsatz_deklarativ(bestellungen): return sum(b['menge'] * b['preis'] for b in bestellungen if ist_verrechenbar(b)) Weder Zwischensumme noch Schleifenkörper sind noch sichtbar – der Code liest sich wie der Satz darüber. Die Bausteine dahinter (''map'', ''filter'', ''reduce'', Comprehensions) behandeln wir ausführlich in LU04. ---- [[https://creativecommons.org/licenses/by-nc-sa/4.0/ch/|{{https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png}}]] (c) Kevin Maurizi