Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

7.2 Schleifen

Humboldt-Universität zu Berlin, Institut für Bibliotheks- und Informationswissenschaft

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_input
stop_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 = 0
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()
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
ausleihe.py
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()