Level 04: Gib mir mein Herz zurück!

Level 4: Gib mir mein Herz zurück! #

Frust with Flags #

Dein Freund Henrik möchte ein Flaggenquiz programmieren, und weil er seinen Code übersichtlich strukturieren möchte, benutzt er unsere Funktion aus dem letzten Level. Meinst du, das funktioniert so? Henrik ist allerdings schon etwas verzweifelt…

def hole_antwort():
    antwort = input('Gib ein: a, b, c oder d: ')
    while not antwort in ['a', 'b', 'c', 'd']:
        antwort = input('Nicht verstanden – a, b, c oder d? ')

print('Willkommen zum Flaggenquiz!')
print('Wo findest du die älteste, heute noch in Gebrauch befindliche Trikolore? ')
print('a) Deutschland b) Frankreich c) Italien d) Niederlande')
hole_antwort()
if antwort == 'd':
    print('Richtig!')
else:
    print('Leider falsch!')

Wenn du den Code ausführst, bricht das Programm plötzlich mit einer Fehlermeldung ab:

Willkommen zum Flaggenquiz!
Welches Land hat die älteste, heute noch in Gebrauch befindliche Trikolore? 
a) Deutschland b) Frankreich c) Italien d) Niederlande
Gib ein: a, b, c oder d: d
Traceback (most recent call last):
  File "<string>", line 10, in <module>
NameError: name 'antwort' is not defined

Woran liegt das? – das Problem #

Übersetzt heißt NameError: name 'antwort' is not defined etwa »Namensfehler: der Name ‘Antwort’ ist nicht definiert.« Die Meldung weist auf Zeile 10, das ist die Zeile, in der mit if antwort == 'd': überprüft werden soll, ob die eingegebene Antwort richtig ist. Doch obwohl die Variable antwort in der Funktion hole_antwort keine Probleme macht, erscheint sie hier als not defined. Die Variable antwort ist hier einfach nicht bekannt.

Der Scope einer Funktion #

Es wird Zeit, dich mit einem Konzept bekannt zu machen, dass Scope genannt wird. Auf Deutsch ließe sich auch Geltungsbereich dazu sagen, doch die meisten Entwickler:innen verwenden die englische Vokabel…

Gleich zu Beginn des Funktionsblocks wird der Variable antwort etwas zugewiesen, und zwar eine Tastatureingabe:

def hole_antwort():
    antwort = input('Gib ein: a, b, c oder d: ')
    # …hier geht die Funktion irgendwie weiter

Entscheidend ist, dass die Variable antwort innerhalb des eingerückten Blocks zu leben beginnt! Damit ist ihr Ende schon fast besiegelt – wenn die Funktion fertig abgearbeitet wurde, wird auch die Variable nicht mehr gebraucht und auf dem Müll entsorgt.

Garbage collection

Hinweis zur Einordnung

Das Bild, das eine Variable »auf dem Müll entsorgt« wird, ist in vielen Programmiersprachen weit verbreitet. Eine Variable braucht (wenn auch nur wenig) Speicherplatz, und um den möglichst gut zu nutzen, kontrolliert die Laufzeitumgebung, die unsere Programme ausführt, immer wieder, welche Variablen nicht mehr gebraucht werden. Von Zeit zu Zeit kommt der Garbage collector (die Müllabfuhr) vorbei, und gibt den Speicherplatz all der nicht mehr benötigten Variablen wieder frei.

Die Lösung: die return-Anweisung! #

Wie bekommen wir die mühsam eingeholte Antwort nur wieder aus der praktischen hole_antwort-Funktion zurück?

Dafür gibt es nun die return-Anweisung. Sobald eine solche Anweisung erreicht wird, bricht die Funktion ab, und liefert was immer hinter return steht an den Aufrufer der Funktion ab.

Meistens ist die return-Anweisung daher am Ende der Funktion zu finden:

def hole_antwort():
    antwort = input('Gib ein: a, b, c oder d: ')
    while not antwort in ['a', 'b', 'c', 'd']:
        antwort = input('Nicht verstanden – a, b, c oder d? ')
    return antwort

Der Aufrufer der Funktion bekommt dann das Ergebnis der Funktion (das was hinter return steht), zurück. Damit kann er machen, was er will: oft wird dieses Ergebnis wieder in einer Variable abgespeichert und weiterverarbeitet. Weil der so gut passende Name antwort außerhalb der Funktion noch nicht besetzt ist, können wir hier diesen Namen verwenden. (Du könntest dir allerdings auch einen ganz anderen ausdenken.)

Hier nun also das funktionierende Program. Siehst du die sehr kleine Änderung vor der Zeile, in der mit if die Antwort ausgewertet wird?

def hole_antwort():
    antwort = input('Gib ein: a, b, c oder d: ')
    while not antwort in ['a', 'b', 'c', 'd']:
        antwort = input('Nicht verstanden – a, b, c oder d? ')
    return antwort

print('Willkommen zum Flaggenquiz!')
print('Wo findest du die älteste, heute noch in Gebrauch befindliche Trikolore? ')
print('a) Deutschland b) Frankreich c) Italien d) Niederlande')
antwort = hole_antwort()
if antwort == 'd':
    print('Richtig!')
else:
    print('Leider falsch!')

Übung: Mensch oder Maschine? #

Du kennst sicher Seiten im Internet, auf denen du unter Beweis stellen sollst, dass du ein Mensch bist, indem du auf Teile von Bildern klickst, verzerrte Buchstaben eingibst oder gesprochene Zahlen erkennst. Wie wäre es, einen eigenen Test zu schreiben?

Schreibe eine Funktion, die dann denn Wahrheitswert True zurückgibt, wenn ein Mensch eine Eingabe macht. Die Funktion könnten wir dann in einem Programm verwenden, z.B. so:

if ist_mensch():
    print('Hallo! Heute einen schönen Tag gehabt?')
else:
    print('Hallo! Heute schon etwas ausgerechnet?')

Wie lässt sich das machen? Wie wäre es damit: viele Menschen sind langsam im Tippen. Wenn deine Testperson länger als fünf Sekunden braucht, um den Satz »Ich bin ein Mensch« zu tippen, glauben wir, dass sie ein Mensch ist. Wird die Antwort schneller eingetippt, unterstellen wir, dass wir es mit einem Computer zu tun haben. (Die sollen ja so schnell sein!)

Das hilft dir sicher dabei:

import time

zeit = time.time()
print(zeit)

time ist ein in Python eingebautes Modul. Mit time.time() können wir die Anzahl der Sekunden ab dem 1.1.1970 erfragen. Zurück kommt eine große Zahl mit vielen Stellen hinter dem Komma.

Tipp 1

Wenn du die Zeit zweimal abrufst, lässt sich die Zeitdauer dazwischen ausrechnen:

import time

zeit_1 = time.time()
input('Gib etwas ein! ')
zeit_2 = time.time()
zeit = zeit_2 - zeit_1
print('So lange hast du gebraucht:', zeit)
Tipp 2

Du könntest eine Variable mit einem Wahrheitswert abspeichern. Ist die ausgerechnete und in zeit abgespeicherte Zeit länger als fünf Sekunden? Dann speichere True in ist_ein_mensch ab. Wenn du vorher False in die Variable geschrieben hattest, wird der Wert geändert, und du kannst die Variable sofort zurückgeben.

def ist_mensch():
    ist_ein_mensch = False
    # …hier bekommst du die Antwortzeit heraus…
    if antwortzeit > 5:
        ist_ein_mensch = True
    return ist_ein_mensch
Tipp 3

Noch kürzer geht es, wenn du das Ergebnis des Vergleichs direkt zurückgibst:

def ist_mensch():
    # …hier bekommst du die Antwortzeit heraus…
    return antwortzeit > 5
Lösungsvorschlag
import time

def ist_mensch():
    zeit_1 = time.time()
    antwort = input('Tippe: "Ich bin ein Mensch", um zu beweisen, dass du ein Mensch bist: ')
    zeit_2 = time.time()
    antwortzeit = zeit_2 - zeit_1
    return antwortzeit > 5

if ist_mensch():
    print('Hallo! Heute einen schönen Tag gehabt?')
else:
    print('Hallo Computer! Heute schon etwas ausgerechnet?')

Zurück Weiter