Im abschließenden Beispiel wiederholen wir zweimal den gleichen Code um zwei verschiedene Eingaben der Nutzer*in abzufragen. Das kann vereinzelt sinnvoll sein, jedoch wollen wir manchmal Code mehrmals häufiger ausführen. Teilweise wissen wir zum Zeitpunkt des Code-Schreibens auch nicht, wie oft Code wiederholt werden soll.
Um all das zu ermöglichen gibt es sogenannte Schleifen (“loops”). In Python
gibt es mehrere Varianten um Code zu wiederholen. Wir sehen uns hier zuerst
einmal die sog. while-Schleifen an.
while-Schleife¶
Eine while-Schleife führt einen Code-Block aus, solange eine Bedingung
gilt. Damit können beispielsweise folgende Handlungen abgebildet werden:
Frage nach einer Eingabe, solange die Eingabe keine Zahl ist.
Wiederhole eine Aktion, solange es nicht regnet.
Würfle eine Zahl, solange sie nicht gerade ist.
…
In (nicht wirklich ausführbarem) Python-Code könnten diese Schleifen wie folgt aussehen:
text = "a"
while not_a_number(text):
text = input("? ")
...while not is_raining():
do_something()
...result = 1
while not (result % 2 == 0):
result = roll_a_die()
print(result)Die hier genutzten Funktionen gibt es so nicht, könnten jedoch programmiert werden.
ausleihe.py¶
Nun kombinieren wir die bisher gelernten Mechanismen in einem Programm, das die Anzahl der entliehenen Medien einer Nutzer*in protokolliert und sowohl ausleihen als auch Rückgaben erlaubt. Bei den Grenzen 0 und 15 Medien werden jeweils Fehlermeldungen ausgegeben und die Buchung wird nicht vollzogen. Ansonsten wird der neue Kontostand ausgegeben.
Wir bauen das Beispiel zuerst Schritt für Schritt auf und am Schluss finden Sie das gesamte Beispiel als Skript. Ab hier werden wir durchgehend englischsprachige Namen nutzen.
Überprüfung der Ober- und Untergrenzen¶
Wir definieren zuerst eine Funktion transact_if_allowed(), welche eine
“Transaktion” (Ausleihen oder Zurückgeben) durchführt, wenn die Grenzen des
Kontostands eingehalten werden. Sie gibt immer den aktuellen, korrekten
Kontostand zurück.
def transact_if_allowed(account_balance, number_of_media):
"""Lend or return media, if within allowed number of media on account.
Parameters
----------
account_balance (int): The current balance before the transaction is attempted.
Valid values: 0 <= x <= 15
number_of_media (int): The number of the media to be lent or returned.
A positive number signifies lending and a negative Number signifies returning.
Returns
-------
int: The current account balance.
"""
new_balance = account_balance + number_of_media
if 0 <= new_balance and new_balance <= 15:
return new_balance
elif new_balance > 15:
print(f"Sie dürfen maximal 15 Medien ausleihen. Sie können noch {15 - account_balance} Medien ausleihen.")
return account_balance
elif new_balance < 0:
print("Sie können nur Medien zurückgeben, die Sie auch ausgeliehen haben.")
print(f"Rückgabe wird abgebrochen.")
return account_balance
else:
print("ERROR: Unreachable.")
print("Account wird zurückgesetzt.")
return 0
help(transact_if_allowed)Help on function transact_if_allowed in module __main__:
transact_if_allowed(account_balance, number_of_media)
Lend or return media, if within allowed number of media on account.
Parameters
----------
account_balance (int): The current balance before the transaction is attempted.
Valid values: 0 <= x <= 15
number_of_media (int): The number of the media to be lent or returned.
A positive number signifies lending and a negative Number signifies returning.
Returns
-------
int: The current account balance.
account = 0
account = transact_if_allowed(account, 2)
account = transact_if_allowed(account, 3)
account = transact_if_allowed(account, 4)
account = transact_if_allowed(account, 5)
account = transact_if_allowed(account, 6)
account = transact_if_allowed(account, -10)
account = transact_if_allowed(account, -10)Sie dürfen maximal 15 Medien ausleihen. Sie können noch 1 Medien ausleihen.
Sie können nur Medien zurückgeben, die Sie auch ausgeliehen haben.
Rückgabe wird abgebrochen.
Abbruchbedingung der Schleife¶
Nachdem wir nun für einen bestimmten Fall entscheiden können, ob eine Entleihe
oder Rückgabe funktioniert wollen wir dies innerhalb einer while-Schleife
tun. Dazu müssen wir uns jedoch überlegen, wann wir die Wiederholung stoppen.
Die Wiederholung soll durch die Interaktion der Nutzer*in ermöglicht werden. Wir können folgendes Interaktionsmuster designen:
$ ./ausleihe.py
Kontostand: 0
Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)
> 4
Kontostand: 4
Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)
> 4
Kontostand: 8
Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)
> q
Programm wird beendet.
$ Betrachten wir zunächst nur die Wiederholung an sich. Eine solche Wiederholung
wird typischerweise umgesetzt, indem eine Variable (bspw. stop_iteration = False) definiert wird, welche unter bestimmte Umständen (hier: die Nutzer*in
hat q eingegeben) auf True gesetzt wird. In der while-Schleife wird diese
Variable dann so genutzt:
stop_iteration = False
while not stop_iteration:
...Implementieren wir dies zusammen mit der Funktion input(), dann könnte dies
wie folgt aussehen:
# CAUTION: Re-defines `input()` for the use with Jupyter Book
# DO NOT RUN THIS CELL WHEN MANUALLY USING THE NOTEBOOK
import builtins
_original_input = builtins.input
_mock_inputs = ["hallo", "3", "q"]
_counter = 0
def mock_input(prompt=""):
global _counter
if _counter < len(_mock_inputs):
val = _mock_inputs[_counter]
print(f"{prompt}{val}")
_counter += 1
return val
return _original_input(prompt) # Fallback
input = mock_inputstop_iteration = False
while not stop_iteration:
text = input("> ")
print(text)
if text == "q":
print("Programm wird beendet.")
stop_iteration = True
> hallo
hallo
> 3
3
> q
q
Programm wird beendet.
Fügen wir nun die Funktion an der richtigen Stelle in der Schleife ein, so erhalten wir folgenden Code:
# DO NOT RUN THIS CELL WHEN MANUALLY USING THE NOTEBOOK
_mock_inputs = ["4", "4", "q"]
_counter = 0account_balance = 0 # This variable stores the account balance for the user
stop_iteration = False
while not stop_iteration:
print("Kontostand:", account_balance)
print("Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)")
text = input("> ")
if text == "q":
print("Programm wird beendet.")
stop_iteration = True
else:
account_balance = transact_if_allowed(account_balance, int(text))
print()Kontostand: 0
Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)
> 4
Kontostand: 4
Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)
> 4
Kontostand: 8
Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)
> q
Programm wird beendet.
Solution to Exercise 1
"q" lässt sich nicht in eine Zahl umwandeln. Es würde dann die Exception
ValueError “geworfen”.
Das Ergebnisskript¶
Solution to Exercise 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76#! /usr/bin/env python3 """ This script allows a user to keep track of their lent and returned books. The following interaction is possible: ```bash $ ./ausleihe.py Kontostand: 0 Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden) > 4 Kontostand: 4 Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden) > 20 Sie dürfen maximal 15 Medien ausleihen. Sie können noch 11 Medien ausleihen. Kontostand: 4 Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden) > -5 Sie können nur Medien zurückgeben, die Sie auch ausgeliehen haben. Rückgabe wird abgebrochen. Kontostand: 4 Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden) > q Programm wird beendet. $ ``` """ def transact_if_allowed(account_balance, number_of_media): """Lend or return media, if within allowed number of media on account. Parameters: ``````````` account_balance (int): The current balance before the transaction is attempted. Valid values: 0 <= x <= 15 number_of_media (int): The number of the media to be lent or returned. A positive number signifies lending and a negative Number signifies returning. Returns: ```````` int: The current account balance. """ new_balance = account_balance + number_of_media if 0 <= new_balance and new_balance <= 15: return new_balance elif new_balance > 15: print(f"Sie dürfen maximal 15 Medien ausleihen. Sie können noch {15 - account_balance} Medien ausleihen.") return account_balance elif new_balance < 0: print("Sie können nur Medien zurückgeben, die Sie auch ausgeliehen haben.") print("Rückgabe wird abgebrochen.") return account_balance else: print("ERROR: Unreachable.") print("Account wird zurückgesetzt.") return 0 if __name__ == "__main__": account_balance = 0 # This variable stores the account balance for the user stop_iteration = False while not stop_iteration: print("Kontostand:", account_balance) print("Wie viele Medien wollen Sie ausleihen/zurückgeben? (q zum Beenden)") text = input("> ") if text == "q": print("Programm wird beendet.") stop_iteration = True else: account_balance = transact_if_allowed(account_balance, int(text)) print()