modul:m323:learningunits:lu07:loesungen:langefunktion

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

modul:m323:learningunits:lu07:loesungen:langefunktion [2026/09/09 11:14] – LU07.L04 - Lange Funktion zerlegen (neu) adminmodul:m323:learningunits:lu07:loesungen:langefunktion [2026/09/09 13:39] (aktuell) – L04 korrigiert: sum() braucht Startwert 0.0, sonst Total 0 statt 0.0 bei leerer Liste admin
Zeile 4: Zeile 4:
  
 <code python> <code python>
-test_bericht.py +main_test.py 
-from bericht import BESTELLUNGEN, bericht+import main
  
 ERWARTET = ( ERWARTET = (
Zeile 18: Zeile 18:
 ) )
  
-def test_bericht_bleibt_gleich(): +def test_bericht_unveraendert(): 
-    assert bericht(BESTELLUNGEN) == ERWARTET+    assert main.bericht(main.BESTELLUNGEN) == ERWARTET
  
-def test_stornierte_werden_ignoriert(): +def test_rabatt_erst_ab_100():
-    nur_storno = [b for b in BESTELLUNGEN if b["status"] == "storniert"+
-    assert "Bestellungen (0)" in bericht(nur_storno) +
- +
-def test_rabattgrenze():+
     knapp_darunter = [{"kunde": "x", "artikel": "a", "menge": 1, "preis": 99.0, "status": "offen"}]     knapp_darunter = [{"kunde": "x", "artikel": "a", "menge": 1, "preis": 99.0, "status": "offen"}]
-    assert "= 99.0 CHF" in bericht(knapp_darunter)+    assert "= 99.0 CHF" in main.bericht(knapp_darunter
 + 
 +def test_rabatt_ab_100_inklusive(): 
 +    genau_100 = [{"kunde": "x", "artikel": "a", "menge": 1, "preis": 100.0, "status": "offen"}] 
 +    assert "a = 95.0 CHF" in main.bericht(genau_100) 
 + 
 +def test_leere_liste(): 
 +    assert main.bericht([]) == ( 
 +        "Bestellungen (0)\n" 
 +        "----------------\n" 
 +        "----------------\n" 
 +        "Total: 0.0 CHF" 
 +    )
 </code> </code>
  
Zeile 35: Zeile 43:
 RABATT_AB_BETRAG = 100 RABATT_AB_BETRAG = 100
 RABATT_PROZENT = 5 RABATT_PROZENT = 5
 +STATUS_STORNIERT = "storniert"
  
  
 def ist_gueltig(bestellung): def ist_gueltig(bestellung):
-    return bestellung["status"] != "storniert"+    return bestellung["status"] != STATUS_STORNIERT
  
  
Zeile 53: Zeile 62:
  
 def zeile(bestellung): def zeile(bestellung):
-    return f"{kundenname(bestellung)}: {bestellung['artikel']} = {round(zeilenwert(bestellung), 2)} CHF"+    artikel = bestellung["artikel"
 +    return f"{kundenname(bestellung)}: {artikel} = {round(zeilenwert(bestellung), 2)} CHF"
  
  
 def bericht(bestellungen): def bericht(bestellungen):
     gueltige = [b for b in bestellungen if ist_gueltig(b)]     gueltige = [b for b in bestellungen if ist_gueltig(b)]
-    total = round(sum(zeilenwert(b) for b in gueltige), 2)+    # Startwert 0.0: sonst liefert sum() bei leerer Liste ein int 
 +    total = round(sum((zeilenwert(b) for b in gueltige), 0.0), 2)
     kopf = f"Bestellungen ({len(gueltige)})"     kopf = f"Bestellungen ({len(gueltige)})"
     strich = "-" * len(kopf)     strich = "-" * len(kopf)
Zeile 71: Zeile 82:
 refactor: Zeilenwert in zeilenwert() extrahiert refactor: Zeilenwert in zeilenwert() extrahiert
 refactor: Namensaufbereitung in kundenname() extrahiert refactor: Namensaufbereitung in kundenname() extrahiert
 +refactor: Zeilenformatierung in zeile() extrahiert
 refactor: Schleife durch Comprehension und sum() ersetzt refactor: Schleife durch Comprehension und sum() ersetzt
 refactor: String-Verkettung durch f-Strings ersetzt refactor: String-Verkettung durch f-Strings ersetzt
 </code> </code>
 +
 +===== Die Falle in dieser Aufgabe =====
 +
 +<WRAP center round important 90%>
 +Der naheliegende Umbau
 +
 +<code python>
 +total = round(sum(zeilenwert(b) for b in gueltige), 2)
 +</code>
 +
 +ist **falsch**. Bei einer leeren Liste liefert ''sum()'' den int ''0'', das Original arbeitet mit ''total = 0.0'' und liefert den float ''0.0''. Der Bericht endet dann mit ''Total: 0 CHF'' statt ''Total: 0.0 CHF''. Richtig ist der Startwert:
 +
 +<code python>
 +total = round(sum((zeilenwert(b) for b in gueltige), 0.0), 2)
 +</code>
 +
 +Der Test ''test_leere_liste'' deckt genau das auf. Ohne ihn wäre die Änderung unbemerkt durchgegangen und später als kosmetischer Bug in der Rechnungsansicht wieder aufgetaucht. **Das ist der Grund, warum das Sicherheitsnetz vor dem ersten Umbau steht.**
 +</WRAP>
  
 ===== Worauf es ankommt ===== ===== Worauf es ankommt =====
Zeile 80: Zeile 110:
   * Die Rabattregel steht an einer Stelle und heisst so, wie die Fachabteilung sie nennt.   * Die Rabattregel steht an einer Stelle und heisst so, wie die Fachabteilung sie nennt.
   * ''bericht'' liest sich jetzt wie eine Inhaltsangabe: filtern, summieren, formatieren.   * ''bericht'' liest sich jetzt wie eine Inhaltsangabe: filtern, summieren, formatieren.
-  * Der Test ''test_rabattgrenze'' deckt genau die Zeile ab, an der ein Vorzeichenfehler (''>'' statt ''>=''unbemerkt bliebe.+  * Die Tests ''test_rabatt_erst_ab_100'' und ''test_rabatt_ab_100_inklusive'' decken die Zeile ab, an der ein ''>'' statt ''>='' unbemerkt bliebe.
  
-<WRAP center round important 80%> +<WRAP center round tip 80%> 
-**Häufiger Fehler:** ''round()'' zu früh anwenden. Wer in ''zeilenwert'' rundet, bekommt beim Total unter Umständen einen anderen Wert als die Vorlage. Runden Sie am Schluss - und prüfen Sie es mit dem Test statt mit dem Auge.+**Zweite Stolperstelle:** ''round()'' zu früh anwenden. Wer in ''zeilenwert'' rundet, bekommt bei anderen Datensätzen Rundungsdifferenzen im Total. Runden gehört an den Schluss.
 </WRAP> </WRAP>
  
  • modul/m323/learningunits/lu07/loesungen/langefunktion.1788945248.txt.gz
  • Zuletzt geändert: 2026/09/09 11:14
  • von admin