Python 101 LN 0 (Null)#

Übungsblatt 0, Punkte: 0

Anliegen dieses LN: So könnte ein Lernprotokoll aussehen. Das hier ist ein Beispiel für ein Lernjournal.

Theorie, Hintergrund#

Es gibt das wunderbare Büchlein “Schreibdenken” von Ulrike Scheuermann.

Herangehensweise im Lernprozess selbst: spielerisches Programmieren. Aber Vorsicht: “Spiel” ist ein Polysem (ein Wort mit mehreren Bedeutungen):

  • Spiel_1: zielorientiert; oft wettbewerblich; meist mit klaren, das Spiel definierende Regeln; mit klaren Erfolgs- und Bewertungsbedingungen; theoretisch bestens erforscht in der mathematischen Spieltheorie … auch sehr interessant in der Programmier-Pädagogik; wir empfehlen hier https://www.codewars.com/

  • Spiel_2: das Spielen eines Kindes; spielerisch als Gegenentwurf zu zielorientiert; EN: playful

Das Adjektiv “spielerisch” verwenden wir im Folgenden ausschließlich in der Bedeutung Spiel_2.

  • Spielerisches Lernen bedeutet nicht Spiel_1: zielorientiert, regelbasiert, wettbewerblich; sondern

  • bedeutet Spiel_2: explorativ, ungezielt, interessante und offene Ziele generierend.

Literatur:

Beispiel: Gegeben sei eine Liste von Klausurnoten zwischen 1 und 5. Aufgabe sei es, den Notenschnitt der bestandenen Klausuren (also 4 oder besser) zu berechnen.

Konventionelles Setting: Schüler erzeugt eine lauffähige Lösung; Dozent vergewissert sich, dass die Lösung für eine Anzahl vorgegebener Tests korrekt ist: “ok, abgehakt”!

Spielerische Herangehensweise: Student findet eine erste Lösung und testet sie mit den vorgegebenen Test: geht!

Jetzt bleibt man aber nicht beim “abhakt” stehen, sondern sucht sich weitere Tests –insbesondere auch solche, die untypisch oder mehr oder weniger “bösartig” sind und dann doch einen Fehler erzeugen.

Soll daraufhin die existierende Lösung umgearbeitet werden? NEIN, die erste Lösung wird als ein Dokument der Zeitgeschichte unverändert belassen. Stattdessen wird eine Kopie der ersten Lösung erzeugt und diese Kopie zur zweiten Lösung weiterentwickelt. Ein Ziel besteht darin, die Lösungen nebeneinander zu sehen, vergleichen, kombinieren, verbessern, und auch auf frühere Lösunen zurückgreifen zu können.

Um die Lösungen zu bewerten stellt man sich traditionell die Frage “Was heißt besser”? Auch hier ist wieder eine spielerische Herangehenswese möglich: technisch “besser” in Bezug auf Laufzeit, Speicherverbrauch? praktisch besser in Bezug auf Lesbarkeit, Wartbarkeit, Erweiterbarkeit, Ähnlichkeit zu anderen Lösungen, Lernwirksamkeit, Kommunizierbarkeit etc.?

Aufgabe 1: Mittelwert von Klausurnoten#

gegeben:

  • eine Liste von Klausurergebnissen

gesucht:

  • Berechne den Mittelwert aller bestandenen Klausuren.

Montag: Initialer Entwurf#

def notenschnitt(notenliste):
    summe = 0
    for zahl in notenliste:
        summe += zahl
    return summe / len(notenliste)

Tests:

ss2023 = [1, 2, 3, 2, 1]
notenschnitt( ss2023 )
1.8

Klappt, Aufgabe gelöst!

Montag Nachmittag#

… Ich war eben einkaufen. Meine Lieblingsschokolade war ausverkauft, schluchz! … dabei ist mir eingefallen: Was macht meine Funktion, wenn ich eine leere Liste übergebe? Denn im ws2023 habe ich ja keine Klausur mitgeschrieben.

ws2023 = []
notenschnitt(ws2023)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[3], line 2
      1 ws2023 = []
----> 2 notenschnitt(ws2023)

Cell In[1], line 5, in notenschnitt(notenliste)
      3 for zahl in notenliste:
      4     summe += zahl
----> 5 return summe / len(notenliste)

ZeroDivisionError: division by zero

Da wird 0 zurückgeliefert: Kein gültiger Durchschnittswert für eine Notenliste, nicht gut. Wir wollen bei einer leeren Liste lieber einen anderen Wert zurückgeben, z.B. False.

def notenschnitt_2(notenliste):
    if len(notenliste) == 0:
       return False
    else:
        summe = 0
        for zahl in notenliste:
            summe += zahl
        return summe / len(notenliste)

print(notenschnitt_2( ss2023 ))
print(notenschnitt_2( ws2023 ))
1.8
False

Mittwoch#

Habe es dem Dozenten gezeigt, ok. Aber Er meint, dass das else unnötig ist, weil das return ja den Funktionsaufruf beendet. Neuer Versuch:

def notenschnitt_3(notenliste):
    if len(notenliste) == 0:
       return False

    summe = 0
    for zahl in notenliste:
        summe += zahl
    return summe / len(notenliste)


print(notenschnitt_3( ss2023 ))
print(notenschnitt_3( ws2023 ))
1.8
False

Im ss2024 hatte ich eine Fünf, eine Zwei und einen Einser. Da nur die bestandenen Klauren zählen, sollte der Schnitt also 1.5 sein:

ss2024 = [5, 2, 1]
print(notenschnitt_3( ss2024 ))
2.6666666666666665

Hm, nicht gut. Was ist das Problem? … ich sehe es nicht, spüle mal das Geschirr vom Vortag ab;

Mittwoch Nachmittag#

Beim Topfschrubben weiß ich plötzlich: Klar, ich muss die Fünfer weglassen! Weiß nicht, wie das geht, habe meinen großen Bruder gefragt, er hat mir das Programm netterweise gleich aufgeschrieben:

ss2024 = [5, 2, 1]
def notenschnitt_4(notenliste):
    gueltig = [ x for x in notenliste if 0 < x < 5  ]
    return False if not len(gueltig) else sum(gueltig) / len(gueltig)

print(notenschnitt_4( ss2024 ))
1.5

Klappt! … aber genau verstehen tue ich nicht, was da steht … da kümmere ich mich später ‘drum ;-)

Aufgabe 2: empirische Varianz#

Wie oben bei Aufgabe 1; jetzt ist aber die empirische Varianz aller bestandenen Klausurnoten gesucht.