Aufgabenblock — AFB III
Begründen statt nur ausführen: Fehlermeldungen deuten, Programme vergleichen, Aussagen beurteilen und Programme weiterentwickeln. Formuliere deine Antwort erst selbst in ganzen Sätzen, bevor du die Musterlösung aufklappst.
Lina erwartet die Ausgabe 11. Stattdessen erscheint 10 und danach eine Fehlermeldung. Erkläre, was passiert, und gib die Korrektur an.
def verdopple(x): print(2 * x)ergebnis = verdopple(5)print(ergebnis + 1)
10 TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Hinweis: Überlege, was in der Variablen ergebnis gespeichert wird.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Die Funktion zeigt 2 · 5 = 10 zwar mit print in der Konsole an, gibt aber nichts zurück. Eine Funktion ohne return liefert den besonderen Wert None. In Zeile 4 wird also ergebnis = None gespeichert. In Zeile 5 soll None + 1 gerechnet werden — das geht nicht, deshalb der TypeError. Richtig ist return 2 * x statt print: Dann ist ergebnis = 10 und die Ausgabe 11.
def verdopple(x): return 2 * xergebnis = verdopple(5)print(ergebnis + 1)
Das Programm soll dreimal einen Stern ausgeben, bricht aber mit TypeError: 'float' object cannot be interpreted as an integer ab. Begründe den Fehler, obwohl 9 durch 3 doch aufgeht, und vergleiche zwei Möglichkeiten der Korrektur.
anzahl = 9for i in range(anzahl / 3): print("*")
Hinweis: Welchen Datentyp liefert / — und welchen braucht range()?
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Der Operator / liefert in Python immer einen float, auch wenn die Division aufgeht: 9 / 3 ergibt 3.0. range() kann aber nur mit ganzen Zahlen (int) zählen — mit 3.0 weiß Python nicht, wie oft wiederholt werden soll. Korrektur 1: anzahl // 3 teilt ganzzahlig und liefert 3. Korrektur 2: int(anzahl / 3) wandelt 3.0 in 3 um. Beide funktionieren hier; // ist kürzer und macht schon beim Lesen klar, dass eine ganze Zahl gemeint ist. Bei anzahl = 10 liefern beide 3 — der Rest fällt jeweils weg.
anzahl = 9for i in range(anzahl // 3): print("*")
Beide Programme geben 2, 4, 6, 8, 10 untereinander aus. Vergleiche sie und erläutere an einem eigenen Beispiel, wann nur eine while-Schleife in Frage kommt.
for zahl in range(2, 11, 2): print(zahl)
zahl = 2while zahl <= 10: print(zahl) zahl = zahl + 2
Hinweis: Frag dich, ob man vor dem Start weiß, wie oft wiederholt wird.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Beide Programme liefern dieselbe Ausgabe. Bei der for-Schleife kümmert sich range(2, 11, 2) um alles: Startwert, Schrittweite und Ende. Bei der while-Schleife muss man den Startwert selbst setzen, die Bedingung formulieren und zahl in der Schleife erhöhen — vergisst man die letzte Zeile, entsteht eine Endlosschleife. Deshalb nimmt man for, wenn die Anzahl der Durchläufe vorher feststeht. while braucht man, wenn eine Bedingung entscheidet und niemand vorher weiß, wie oft es nötig ist — zum Beispiel eine PIN-Abfrage, die so lange wiederholt wird, bis die richtige PIN kommt:
pin = input("PIN? ")while pin != "1234": print("Falsch, noch einmal.") pin = input("PIN? ")print("Entsperrt!")
Ein Porto-Programm soll für Briefe bis 500 g „Kompaktbrief“ ausgeben. Bei 300 g erscheint aber „Großbrief“. Begründe, warum der elif-Zweig nie ausgeführt werden kann, und korrigiere das Programm.
gewicht = 300if gewicht <= 1000: print("Großbrief: 1.80 Euro")elif gewicht <= 500: print("Kompaktbrief: 1.10 Euro")else: print("Paket")
Hinweis: Ein Brief mit 300 g ist auch leichter als 1000 g.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Python prüft von oben nach unten und führt nur den ersten wahren Zweig aus. Jedes Gewicht, das kleiner oder gleich 500 ist, ist automatisch auch kleiner oder gleich 1000. Damit ist schon die erste Bedingung wahr, und der elif-Zweig wird gar nicht mehr geprüft — er kann nie laufen. Man muss die engere Bedingung zuerst prüfen:
gewicht = 300if gewicht <= 500: print("Kompaktbrief: 1.10 Euro")elif gewicht <= 1000: print("Großbrief: 1.80 Euro")else: print("Paket")
Tarek behauptet: „Die Variable i wird in jedem Durchlauf verändert — also kann das keine Endlosschleife sein.“ Beurteile die Aussage.
i = 0while i != 10: print(i) i = i + 3
Hinweis: Schreib die ersten Werte von i auf.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Tareks Aussage stimmt so nicht. Dass sich i ändert, ist nötig, reicht aber nicht aus: Die Bedingung muss irgendwann falsch werden. i nimmt die Werte 0, 3, 6, 9, 12, 15, … an und springt an der 10 vorbei. Deshalb ist i != 10 immer wahr, und das Programm läuft endlos. Mit while i < 10: endet es nach der Ausgabe 0, 3, 6, 9. Allgemein: Bei Schleifen mit Schrittweite ist < bzw. > sicherer als !=.
Nach der Eingabe 15 erscheint die Meldung unten. Erkläre die Fehlermeldung und begründe, warum der eigentliche Fehler nicht in Zeile 2, sondern in Zeile 1 steckt.
alter = input("Wie alt bist du? ")if alter >= 16: print("Du darfst allein ins Kino.")
Traceback (most recent call last):
File "programm.py", line 2, in <module>
if alter >= 16:
TypeError: '>=' not supported between instances of 'str' and 'int'
Hinweis: Lies die letzte Zeile der Meldung zuerst.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Die letzte Zeile nennt die Fehlerart TypeError: Der Vergleich >= ist zwischen einem str und einem int nicht möglich. Darüber steht „line 2“ — dort bricht Python ab. Der str ist die Variable alter: input() liefert immer Text, also ist alter = "15". Zeile 2 ist korrekt geschrieben; falsch ist, dass in Zeile 1 die Umwandlung in eine Zahl fehlt. Korrektur: alter = int(input("Wie alt bist du? ")). Merke: Die gemeldete Zeile zeigt, wo es knallt, die Ursache kann weiter oben liegen.
Egal, was man eintippt — auch bei „nein“ erscheint „Neue Runde!“. Python meldet keinen Fehler. Erkläre dieses Verhalten und gib zwei korrekte Schreibweisen an.
antwort = input("Weiterspielen? ")if antwort == "ja" or "Ja": print("Neue Runde!")else: print("Tschüss!")
Hinweis: Python liest die Bedingung nicht so, wie wir sie sprechen.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Python wertet (antwort == "ja") or "Ja" aus. Rechts von or steht keine Bedingung, sondern nur der Text "Ja" — und ein nicht leerer Text zählt in einer Bedingung als wahr. Damit ist die ganze or-Verknüpfung immer wahr, der else-Zweig läuft nie. Weil das Programm trotzdem ohne Meldung läuft, ist das ein logischer Fehler. Richtig: if antwort == "ja" or antwort == "Ja": — beide Seiten sind vollständige Vergleiche. Noch kürzer: if antwort.lower() == "ja":, das fängt auch „JA“ ab.
Das Programm soll „Mund“ ausgeben, bricht aber mit TypeError: 'str' object does not support item assignment ab. Erkläre den Fehler, entwickle zwei verschiedene korrekte Lösungen und vergleiche sie.
tier = "Hund"tier[0] = "M"print(tier)
Hinweis: Bei einer Liste würde liste[0] = "M" funktionieren.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Zeichenketten sind in Python unveränderbar: Man kann ein einzelnes Zeichen lesen (tier[0]), aber nicht überschreiben. Deshalb der TypeError. Man muss einen neuen String bilden und in der Variablen speichern. Lösung 1 setzt ihn aus „M“ und dem Rest ab Index 1 zusammen: tier = "M" + tier[1:]. Lösung 2 nutzt tier = tier.replace("H", "M"). Beide liefern „Mund“. Unterschied: Lösung 1 ersetzt genau das erste Zeichen, egal welches es ist; replace ersetzt jedes „H“ im Wort — bei „HaHa“ würden beide ersetzt.
tier = "Hund"tier = "M" + tier[1:]print(tier)
Die Funktion soll True liefern, wenn in der Liste mindestens eine negative Zahl steht. Für [-1, 2] klappt es. Überprüfe die Funktion mit [3, -5], erkläre das Ergebnis und korrigiere sie.
def hat_negative(zahlen): for z in zahlen: if z < 0: return True else: return False
Hinweis: Überlege, wie oft die Schleife höchstens läuft.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Beim Aufruf mit [3, −5] ist z zuerst 3. 3 < 0 ist falsch, also läuft der else-Zweig mit return False — und return beendet die Funktion sofort. Die −5 wird nie angeschaut, das Ergebnis False ist falsch. Die Funktion prüft also in Wahrheit nur das erste Element. Richtig ist: Sobald eine negative Zahl gefunden ist, sofort True zurückgeben; False erst dann, wenn die Schleife ganz durchgelaufen ist, also nach der Schleife:
def hat_negative(zahlen): for z in zahlen: if z < 0: return True return False
Im Quiz-Projekt soll jede Frage einen zweiten Versuch bekommen. Entwickle eine Funktion frage(text, loesung), die höchstens zweimal fragt und True oder False zurückgibt, und begründe, warum die Funktion return statt print verwenden sollte.
Hinweis: Die Funktion soll selbst nichts zählen — das macht das Hauptprogramm.
Musterlösung anzeigen (zählt als erledigt)
Musterlösung: Die Funktion fragt in einer Schleife höchstens zweimal. Ist die Antwort richtig, beendet return True die Funktion sofort — ein zweiter Versuch ist dann nicht mehr nötig. Erst wenn beide Versuche falsch waren, erreicht Python die Zeile nach der Schleife und gibt False zurück. Weil frage() einen Wahrheitswert zurückgibt, kann das Hauptprogramm damit weiterarbeiten: if frage(…): erhöht die Punkte. Mit print würde das Ergebnis nur angezeigt; das Hauptprogramm bekäme None und könnte nicht zählen. Außerdem bleibt die Funktion so für jede Frage wiederverwendbar.
def frage(text, loesung): for versuch in range(2): antwort = input(text + " ") if antwort.strip().lower() == loesung: return True print("Leider falsch.") return Falsepunkte = 0if frage("Wie viele Bits hat ein Byte?", "8"): punkte = punkte + 1if frage("Welche Farbe entsteht aus Blau und Gelb?", "grün"): punkte = punkte + 1print("Punkte:", punkte)
