Dies ist eine alte Version des Dokuments!


LU01.L09 - Vom Skript zur Funktion

Alle drei def-Blöcke sind Prozeduren:

Block Warum Prozedur?
artikel_hinzufuegen Kein return. Wirkt nach aussen: verändert die globale Liste lager und die globale Zahl gesamtwert.
zeige_gesamtwert Kein return. Wirkt nach aussen: schreibt auf die Konsole. Liest zudem globalen Zustand statt Parameter.
zeige_teuersten Kein return. Berechnet zwar etwas, gibt es aber nicht heraus, sondern druckt es direkt.

Alle drei geben None zurück und lassen sich deshalb nicht als Ausdruck verwenden.

def artikel_hinzufuegen(lager, name, menge, preis):
    """Gibt ein NEUES Lager mit dem zusätzlichen Artikel zurück."""
    return lager + [{"name": name, "menge": menge, "preis": preis}]
 
 
def gesamtwert(lager):
    """Berechnet den Gesamtwert aller Artikel im Lager."""
    total = 0
    for artikel in lager:
        total += artikel["menge"] * artikel["preis"]
    return total
 
 
def teuerster_artikel(lager):
    """Gibt den teuersten Artikel zurück, bei leerem Lager None."""
    if not lager:
        return None
    teuerster = lager[0]
    for artikel in lager[1:]:
        if artikel["preis"] > teuerster["preis"]:
            teuerster = artikel
    return teuerster
 
 
def formatiere_gesamtwert(lager):
    """Erzeugt den Ausgabetext - gibt ihn zurück, statt ihn zu drucken."""
    return f"Gesamtwert: {gesamtwert(lager):.2f} CHF"
 
 
if __name__ == '__main__':
    lager = []
    lager = artikel_hinzufuegen(lager, 'Maus', 10, 24.90)
    lager = artikel_hinzufuegen(lager, 'Tastatur', 4, 79.50)
    lager = artikel_hinzufuegen(lager, 'Monitor', 2, 249.00)
 
    print(formatiere_gesamtwert(lager))              # Gesamtwert: 1065.00 CHF
    print(f"Teuerster Artikel: {teuerster_artikel(lager)['name']}")  # Monitor
 
    # Nachweis 1: derselbe Aufruf liefert immer dasselbe Ergebnis
    print(gesamtwert(lager) == gesamtwert(lager))    # True
 
    # Nachweis 2: das Original bleibt unverändert
    erweitert = artikel_hinzufuegen(lager, 'Dock', 1, 189.00)
    print(len(lager), len(erweitert))                # 3 4
 
    # Randfall: leeres Lager
    print(teuerster_artikel([]))                     # None

Zum + in artikel_hinzufuegen

lager + [neuer_artikel] erzeugt eine neue Liste, lager.append(…) verändert die bestehende. Genau darin liegt der Unterschied zwischen der funktionalen und der prozeduralen Variante.

Der Preis: Die aufrufende Stelle muss das Ergebnis auffangen (lager = artikel_hinzufuegen(…)). Wer das vergisst, verliert den neuen Artikel – dafür kann er aber nie versehentlich fremde Daten beschädigen.

gesamtwert(lager) hängt nur von seinem Parameter ab und verändert nichts. Der Aufruf kann darum jederzeit im Kopf durch seine Zahl ersetzt werden – das Programm verhält sich identisch. Diese Eigenschaft heisst referenzielle Transparenz.

Beim alten artikel_hinzufuegen('Maus', 10, 24.90) geht das nicht: Der Aufruf hat gar keinen Rückgabewert, den man einsetzen könnte, und seine Wirkung hängt davon ab, was vorher schon im globalen lager stand. Man muss die ganze Vorgeschichte des Programms kennen, um zu wissen, was passiert.

ergebnis = zeige_gesamtwert()
print(ergebnis)     # None

Eine Prozedur ohne return liefert in Python implizit None. Die Zahl war zwar auf der Konsole zu sehen, ist im Programm aber nirgends mehr greifbar – sie lässt sich nicht weiterverwenden, nicht weiterrechnen und nicht testen.

Automatisch testbar sind gesamtwert, teuerster_artikel, artikel_hinzufuegen und formatiere_gesamtwert: Man ruft sie mit einer bekannten Eingabe auf und vergleicht den Rückgabewert mit dem erwarteten Wert.

def test_gesamtwert():
    lager = [{"name": "A", "menge": 2, "preis": 10.0}]
    assert gesamtwert(lager) == 20.0
 
def test_teuerster_bei_leerem_lager():
    assert teuerster_artikel([]) is None

Die alten Prozeduren lassen sich so nicht prüfen: Sie geben nichts zurück. Man müsste die Konsolenausgabe abfangen und zusätzlich den globalen Zustand vor jedem Test zurücksetzen – aufwendig und fehleranfällig. Das ist der praktische Grund, warum die funktionale Programmierung Berechnung und Ausgabe trennt.


© Kevin Maurizi

  • modul/m323/learningunits/lu01/loesungen/prozedurzufunktion.1787040519.txt.gz
  • Zuletzt geändert: 2026/08/18 10:08
  • von admin