Python 101 LN 2#

Familienname:

Vorame:

HAW-Account:

MatNr:

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

Theorie, Hintergrund#

Ein wichtiger Modus des Lernens ist spielerisches Programmieren. Man kann auf verschiedene Weisen spielen, “Spiel” ist ein Wort mit mehreren Bedeutungen (ein Polysem):

  • 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#

Hier ein Beispiel für spielerisches Lernen.

Gegeben:

  • eine Liste von Klausurnoten zwischen 1 und 5.

Gesucht:

  • 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 oberflächlich: 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_1(notenliste):
    summe = 0
    for zahl in notenliste:
        summe += zahl
    return summe / len(notenliste)

Tests:

ss2023 = [1, 2, 3, 2, 1]
notenschnitt_1( 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_1(ws2023)  # Auskommentiert, um keinen wirklichen Fehler zu erzeugen

Es wird ein Fehler geworfen. Das ist der Fehlertext:

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

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

ZeroDivisionError: division by zero

Bei einer leeren Liste wird ein Fehler geworfen – 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):
    # Lösung vom großen Bruder 'reinkopiert
    # nicht verwendbar, wenn man sie nicht wirklich erklären kann!
    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

Besser#

Nachgedacht: Es ist keine gute Idee, das Wegstreichen von Fünfern in die Funktion mit ‘reinzunehmen. Besser zwei Funktionen, sie man unabhängig voneinander nutzen kann.

def nur_gueltige(notenliste, *, min=1, max=4):
    ng = [ x for x in notenliste if x >= min and x <= max ]
    return ng
def notenschnitt(notenliste):
    if not notenliste:
        return False
    else:
        return sum(notenliste) / len(notenliste)
notenschnitt( nur_gueltige( ss2024 ) )
1.5
notenschnitt( nur_gueltige( [] ))
False

Aufgabe 2: empirische Varianz#

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

Vorgehen:

  • Beginnen Sie mit einer Notenliste, z.B. l_alle = [ 1, 5, 3, 1 ].

  • Erzeugen Sie daraus die Liste l_gueltig aller gültigen Noten.

  • Berechnen Sie aus l_gueltig den Mittelwert avg.

  • Erzeugen Sie auf Basis der Liste l_gueltig die Liste der quadrierte Abstände l_qa (): für jeden Wert aus l_gueltig wird sein quadrierter Abstand zum Mittelwert avg berechnet.

  • Berechnen Sie die Summe aus l_qa – das ist dann die gesuchte Summe aller Quadrierten Abstände.

  • Berechnen Sie die empirische Varianz.

Wir haben zu Ihrer Bequemlichkeit die entsprechenden Zellen schon für Sie vorbereitet.

Beginnen Sie mit einer eigenen Notenliste#

z.B. l_alle = [ 1, 5, 3, 1 ]. Oder eine andere Notenliste – idealerweise eine solche,

  • die niemand anderes im Kurs hat – Abschreiben vermeiden ;-) ,

  • aber die kurz genug ist, dass Sie den Schnitt selbst berechnen können.

Erzeugen Sie daraus die Liste l_gueltig aller gültigen Noten.#

Berechnen Sie aus l_gueltig den Mittelwert avg.#

Erzeugen Sie auf Basis der Liste l_gueltig die Liste der quadrierte Abstände l_qa ()#

Für jeden Wert aus l_gueltig wird sein quadrierter Abstand zum Mittelwert avg berechnet.

Berechnen Sie die Summe aus l_qa#

Das ist dann die gesuchte Summe aller Quadrierten Abstände.

Berechnen Sie die empirische Varianz.#