Nun wollen wir alles bisher gelernte zusammenführen und das Skript taschenrechner.py entwickeln.
Dazu werden wir zuerst eine einzelne “Rechen-Interaktion” programmieren und diese dann in einer Schleife wiederholen. Abschließend erstellen wir daraus wieder ein ausführbares Skript.
Für die Implementierung bleiben folgende Fragen zu klären:
Welche Operatoren sind erlaubt? Wie werden diese erkannt und wie wird die korrekte Funktionalität in Python ausgelöst?
Welche Zahlen-Datentypen werden akzeptiert? Wie wird mit Eingaben, die nicht in eine Zahl umgewandelt werden können, umgegangen?
Recheninteraktion¶
Eine Recheninteraktion soll wie folgt gestaltet sein:
Es wird ein mathematischer Operator abgefragt.
Es wird mindestens ein Operand abgefragt.
Das Ergebnis der Berechnung wird ausgegeben.
“naive” Implementierung¶
Nehmen wir zuerst einmal an, dass die Nutzer*innen keine Fehler machen und wir nur Eingaben erhalten, die unserem Design entsprechen. Nehmen wir weiter an, dass die Addition von zwei Operanden durchgeführt werden soll.
Wir implementieren die Funktion calculate(), die drei Nutzer*innen-Eingaben einliest und das Ergebnis der Berechnung zurück gibt.
Dabei orientieren wir uns an dieser Beispielinteraktion:
> +
>> 3
>> 4
>>
7
def calculate():
operator = input("> ")
op1 = int(input(">> "))
op2 = int(input(">> "))
empty = input(">> ")
return op1 + op2
Ob alles funktioniert hat können Sie mit dem nachfolgenden Code testen. Das assert-Statement überprüft, ob der erste Ausdruck wahr ist. Wenn nein, dann wird der zweite Ausdruck als AssertionError() ausgegeben.
assert 35 == calculate(), "Operator: +, Operand 1: 10, Operand 2: 25 FEHLER: Nicht erfolgreich"> +
>> 10
>> 25
>>
Diese Implementierung ignoriert aktuell die Eingabe des Operators. Dann werden zwei Zahlen eingelesen und als Ganzzahl interpretiert. Es folgt das einlesen einer leeren Zeile, welche das Ende der Operanden-Eingabe signalisiert und es wird - hart codiert - das Ergebnis der Berechnung zurückgegeben.
# TIPPEN SIE DIESEN CODE AB UND ÄNDERN SIE IHN DANN
def calculate():
operator = input("> ")
op1 = int(input(">> "))
op2 = int(input(">> "))
empty = input(">> ")
return op1 + op2assert 35 == calculate(), "Operator: '+', Operand 1: 10, Operand 2: 25 FEHLER: Nicht erfolgreich"
assert calculate() is None, "Operator: '-' sollte als Fehler erkannt werden"> +
>> 10
>> 25
>>
> -
>> 1
>> 1
>>
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[6], line 2
1 assert 35 == calculate(), "Operator: '+', Operand 1: 10, Operand 2: 25 FEHLER: Nicht erfolgreich"
----> 2 assert calculate() is None, "Operator: '-' sollte als Fehler erkannt werden"
AssertionError: Operator: '-' sollte als Fehler erkannt werdenSolution to Exercise 1
def calculate():
operator = input("> ")
if operator != "+":
return None
op1 = int(input(">> "))
op2 = int(input(">> "))
empty = input(">> ")
return op1 + op2assert 35 == calculate(), "Operator: '+', Operand 1: 10, Operand 2: 25 FEHLER: Nicht erfolgreich"
assert calculate() is None, "Operator: '-' sollte als Fehler erkannt werden"> +
>> 10
>> 25
>>
> -
Korrekte Behandlung der Operanden¶
Bisher gehen wir immer von genau 2 Operanden (und einer leeren Eingabe) aus. Der nächste Schritt ist es, eine variable Anzahl von Operanden einzulesen.
Konzeptionell wollen wir also:
eine Eingabe der Nutzer*in einlesen,
überprüfen, ob diese leer ist und ggf. das einlesen beenden
ansonsten die Eingabe in eine Zahl umwandeln und
zwischenspeichern, bis alle Zahlen eingelesen sind.
Um mehrere Werte in einer Variablen zu speichern lernen wir einen neuen Datentyp kennen: die Liste (list(), []). Eine Liste kann mehrere Werte enthalten und es können Werte am Ende hinzugefügt werden. Dann kann die Liste durchlaufen werden und mit jedem Wert etwas getan werden.
Verkleinern wir das Problem noch weiter, so wollen wir diese Interaktion ermöglichen:
>> 1
>> 2
>> 3
>>Am Ende dieser Eingaben sollten die Werte 1, 2 und 3 in einer Liste gespeichert sein. Das kann beispielsweise so aussehen:
numbers = [] # define an empty list to store the numbers
while True: # loop indefinitely until we `break` out on empty input
text = input(">> ")
if "" == text:
break
else:
number = int(text)
numbers.append(number) # append entered number to list of numbers
numbers # the last value of a cell is printed as its result>> 1
>> 2
>> 3
>>
[1, 2, 3]Solution to Exercise 2
def calculate():
operator = input("> ")
if operator != "+":
return None
numbers = []
while True:
text = input(">> ")
if "" == text:
break
numbers.append(int(text))
op1 = numbers[0]
op2 = numbers[1]
return op1 + op2assert 3 == calculate(), "ERROR: '+', '1', '2', '3', '' : Not handled correctly"
assert calculate() is None, "ERROR: Operator '-' is not allowed"> +
>> 1
>> 2
>> 3
>>
> -
Nun haben wir es fast geschafft. Es fehlt nur noch die korrekte Behandlung mehrerer Operanden bei der Berechnung des Ergebnisses.
Verkleinern wir das Problem wieder, so können wir eine Variable erstellen, welche am Schluss das Ergebnis beinhalten soll und anschließend können wir für alle Operanden das Ergebnis mit dem Operanden verrechnen. Am einfachsten geht das mit der sogenannten for-Schleife:
numbers = [1, 2, 3]
result = 0
for number in numbers:
result += number
result6Solution to Exercise 3
def calculate():
# handle the operator
operator = input("> ")
if operator != "+":
return None
# read in the operands
numbers = []
while True:
text = input(">> ")
if "" == text:
break
numbers.append(int(text))
# calculate result
if operator == "+":
result = 0
for number in numbers:
result += number
return resultassert 6 == calculate(), "ERROR: '+', '1', '2', '3', '' : Not handled correctly"
assert 3 == calculate(), "ERROR: '+', '1', '2', '' : Not handled correctly"
assert calculate() is None, "ERROR: Operator '-' is not allowed"> +
>> 1
>> 2
>> 3
>>
> +
>> 1
>> 2
>>
> -
Solution to Exercise 4
Eingabe 1:
> +
>>
0Es wird kein Operand angegeben. Daher wird die for-Schleife kein Mal durchlaufen. Der Wert von result wird jedoch schon vor der Schleife auf 0 gesetzt, weshalb dieser Wert dann auch zurückgegeben wird.
Eingabe 2:
> +
>> 1
>>
1Es wird 0+1 gerechnet.
Die Programmschleife¶
Die Programmschleife soll in jedem Schritt:
die Recheninteraktions-Funktion aus dem vorherigen Abschnitt aufrufen und
das Rechenergebnis ausgeben, falls vorhanden
die Schleife soll beendet werden, wenn kein Operator übergeben wurde
Für die Lösung dieses Problems lernen wir noch ein weiteres sehr nützliches Syntaxelement von Python kennen – den sogenannten Walross-Operator :=.
Dieser erlaubt es in den Bedingungen von if, while, usw. das Ergebnis der Bedingung in einer Variablen abzuspeichern. Dadurch kann unsere Programmschleife wie folgt aussehen:
while result := calculate():
print(result)> +
>> 1
>> 2
>>
3
> +
>> 1
>>
1
>
Gestaltung als Skript¶
Solution to Exercise 5
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#! /usr/bin/env python3 def calculate(): # handle the operator operator = input("> ") if operator != "+": # print("ERROR: Unknown operator.") return None # read in the operands numbers = [] while True: text = input(">> ") if "" == text: break numbers.append(int(text)) # calculate result if operator == "+": result = 0 for number in numbers: result += number return result if __name__ == "__main__": while result := calculate(): print(result)
!echo "Testing the script automatically with the input: + 3 4"
!chmod u+x ../solutions/020/taschenrechner.py
print('Simulate user interaction by running command in terminal:\n$ echo "+\\n3\\n4\\n\\n" | ./taschenrechner.py')
!echo "+\n3\n4\n\n" | ../solutions/020/taschenrechner.pyTesting the script automatically with the input: + 3 4
Simulate user interaction by running command in terminal:
$ echo "+\n3\n4\n\n" | ./taschenrechner.py
> Der Befehl echo “tippt” die Zeichenfolge, die danach folgt in die sog. Standardausgabe. Diese wird dann über eine sog. pipe (|) an das Skript ./taschenrechner.py umgeleitet, wodurch eine Nutzer*innen-Interaktion simuliert werden kann.