Vorlesungsskript 17
Einfache CLIs und TUIs mit Python
Ein Programm mit einem gut gestalteten Benutzerinterface ist leichter und angenehmer zu benutzen. Das gilt nicht nur für grafische, sondern auch für textbasierte Benutzerinterfaces. Ein Programm mit einem guten Kommandozeileninterface (CLI) erlaubt es der Benutzerin zum Beispiel, den Input wahlweise über den Standard-Input oder in Dateien zur Verfügung zu stellen. Und mit Hilfe von textbasierten Benutzerinterfaces (TUIs) lassen sich einfache interaktive Programme realisieren. In diesem Vorlesungsskript lernen Sie einige Werkzeuge kennen, die Python zur Verfügung stellt, um Ihre Programme mit guten CLIs und TUIs zu versehen.
Kommandozeilenargumente verarbeiten
Bisher haben wir alle unsere Python-Programme ohne Argumente aufgerufen. Ihr Output wurde ausschließlich von den Daten beeinflusst, die wir den Programmen über den Standard-Input mitgegeben haben oder die sie aus Dateien gelesen haben. Aber so wie die Unix-Standardprogramme können auch Python-Programme Kommandozeilenargumente verarbeiten, die ihr Verhalten beeinflussen.
Für diesen Zweck gibt es im Modul sys
die Variable
argv
(für argument values). Sie enthält eine
Liste mit den Kommandozeilenargumenten, die der Benutzer eingegeben hat. Am Index
0 steht dabei der Name des Python-Programms selbst, an den folgenden Indizes die
eigentlichen Argumente. Hier ist ein Testprogramm, myprog.py
,
das das demonstriert:
import sys
print(sys.argv)
Wenn wir es von der Kommandozeile aus aufrufen, gibt es die Argumentliste aus:
$ python3 myprog.py
['myprog.py']
$ python3 myprog.py myfile.txt
['myprog.py', 'myfile.txt']
$ python3 myprog.py dog cat mouse
['myprog.py', 'dog', 'cat', 'mouse']
Wir werden sys.argv
nun benutzen, um unser Beispielprogramm
linenum.py
zu verbessern. In der vorigen Version hatte es seinen
Input immer aus der Datei moby-dick.txt
gelesen. Nun erwartet es
stattdessen einen Pfad zu einer Datei als Argument und liest den Input dann aus der angegebenen
Datei:
import sys
infile = open(sys.argv[1], 'r')
i = 0
for line in infile:
i += 1
print(i, line, end='')
infile.close()
So kann eine Benutzerin es aufrufen:
$ python3 linenum.py moby-dick.txt | tail
23856 And King of the boundless sea."
23857 --WHALE SONG.
23858
23859
23860
23861
23862
23863 End of The Project Gutenberg Etext of Moby Dick, by Herman Melville
23864
23865
$ python3 linenum.py alice-in-wonderland.txt | tail
3844 she would keep, through all her riper years, the simple and
3845 loving heart of her childhood: and how she would gather about
3846 her other little children, and make THEIR eyes bright and eager
3847 with many a strange tale, perhaps even with the dream of
3848 Wonderland of long ago: and how she would feel with all their
3849 simple sorrows, and find a pleasure in all their simple joys,
3850 remembering her own child-life, and the happy summer days.
3851
3852 THE END
3853
Wir können das Programm auch mit Hilfe einer Schleife in die Lage versetzen, mehrere Dateien als Argumente zu nehmen und zu lesen:
import sys
i = 0
for path in sys.argv[1:]:
infile = open(path, 'r')
for line in infile:
i += 1
print(i, line, end='')
infile.close()
So kann ein Benutzer das Programm jetzt aufrufen:
$ python3 linenum.py moby-dick.txt alice-in-wonderland.txt | tail
27709 she would keep, through all her riper years, the simple and
27710 loving heart of her childhood: and how she would gather about
27711 her other little children, and make THEIR eyes bright and eager
27712 with many a strange tale, perhaps even with the dream of
27713 Wonderland of long ago: and how she would feel with all their
27714 simple sorrows, and find a pleasure in all their simple joys,
27715 remembering her own child-life, and the happy summer days.
27716
27717 THE END
27718
Variabler Input mit fileinput
Wir können der Benutzerin auch die Wahl geben, ob sie als Input einen oder
mehrere Dateipfade oder den Standard-Input angeben möchte, so wie viele
Standardprogramme das tun. Dazu steht im Modul fileinput
die Funktion input
zur Verfügung. Diese Funktion
prüft selbständig, ob Argumente übergeben wurden. Wenn ja,
liest sie die entsprechenden Dateien und gibt ein Iterable über
deren Zeilen zurück. Wenn nein, liest sie den Standard-Input
und gibt ein Iterable über dessen Zeilen zurück. Somit können
wir unser Programm wie folgt umschreiben:
import fileinput
i = 0
for line in fileinput.input():
i += 1
print(i, line, end='')
Jetzt kann die Benutzerin dem Programm seinen Input auf beide Weisen übergeben: entweder per Standard-Input (z.B. mit einer Pipe) oder als Datei(en):
$ cat moby-dick.txt alice-in-wonderland.txt | python3 linenum.py | tail
27709 she would keep, through all her riper years, the simple and
27710 loving heart of her childhood: and how she would gather about
27711 her other little children, and make THEIR eyes bright and eager
27712 with many a strange tale, perhaps even with the dream of
27713 Wonderland of long ago: and how she would feel with all their
27714 simple sorrows, and find a pleasure in all their simple joys,
27715 remembering her own child-life, and the happy summer days.
27716
27717 THE END
27718
$ python3 linenum.py moby-dick.txt alice-in-wonderland.txt | tail
27709 she would keep, through all her riper years, the simple and
27710 loving heart of her childhood: and how she would gather about
27711 her other little children, and make THEIR eyes bright and eager
27712 with many a strange tale, perhaps even with the dream of
27713 Wonderland of long ago: and how she would feel with all their
27714 simple sorrows, and find a pleasure in all their simple joys,
27715 remembering her own child-life, and the happy summer days.
27716
27717 THE END
27718
Interaktive Eingaben mit input
Die eingebaute Funktion input
(nicht zu verwechseln mit
fileinput.input
) ermöglicht es, Eingaben vom Benutzer abzufragen,
während das Programm bereits läuft. Hiermit lassen sich also interaktive Programme mit
TUIs (text user interfaces) schreiben.
Die Funktion input
wird mit einem String als
Argument aufgerufen. Diesen benutzt sie als „Prompt“, um die Benutzerin zu
einer Eingabe aufzufordern. Dann wartet input
darauf,
dass die Benutzerin etwas eingibt und Enter drückt. Schließlich gibt input
die Eingabe als String zurück.
Hier ist ein Beispielprogramm (add.py
), das die
Benutzerin um die Eingabe zweiter Zahlen bittet und diese dann addiert:
number1 = input('Please enter a number: ')
number1 = int(number1)
number2 = input('Please enter another number: ')
number2 = int(number2)
total = number1 + number2
print('The sum is:', total)
So wird es benutzt:
$ python3 add.py
Please enter a number: 2
Please enter another number: 3
The sum is: 5
while
-Schleifen
Interaktive Programme bitten den Benutzer häufig mehrfach um eine Eingabe – in vielen Fällen immer wieder, so lange, bis der Benutzer das Programm beendet. Beispiele sind die Unix-Shell und der Python-Interpreter: beide zeigen immer wieder ein neues Prompt an und erwarten eine neue Eingabe, bis der Benutzer sie beendet.
In Python können wir dieses Verhalten mit while
-Schleifen umsetzen.
Wie for
-Schleifen sind while
-Schleifen
Blockanweisungen mit einem Kopf und einem Körper, der mehrfach ausgeführt wird. Der Kopf einer
while
-Schleife lautet im einfachsten Fall wie folgt:
while True:
Der Körper einer solchen Schleife wird immer wieder wiederholt, bis die Anweisung
break
ausgeführt wird.
Hier ist ein Beispielprogramm (even.py
), das den
Benutzer wiederholt um die Eingabe einer Zahl bittet und anschließend ausgibt,
ob die Zahl gerade oder ungerade ist:
while True:
number = input('Please enter an integer: ')
if not number:
break
number = int(number)
if number % 2 == 0:
print(number, 'is even.')
else:
print(number, 'is odd.')
Das sieht dann zum Beispiel so aus:
$ python3 even.py
Please enter a number: 3
3 is odd.
Please enter a number: 16
16 is even.
Please enter a number:
Die Wiederholung ist mit einer while
-Schleife
umgesetzt. Im Körper dieser Schleife wird zunächst die Benutzerin um die Eingabe
einer Ganzzahl gebeten. Gibt sie nichts ein, gibt die input
-Methode
den leeren String zurück. Das wird mit Hilfe der folgenden Verzweigung geprüft. Falls nichts
eingegeben wurde, wird die Schleife abgebrochen. Ansonsten wird die Ausführung des Schleifenkörpers
fortgesetzt, es wird ausgegeben, ob die Zahl gerade oder ungerade ist, und dann beginnt die
Ausführung des Schleifenkörpers wieder von vorn.
Das True
in while True:
ist eine Bedingung. Vor jeder Ausführung des Schleifenkörpers wird diese
Bedingung geprüft. Gibt sie einen „falsy“ Wert zurückt, wird die Schleife
abgebrochen.
Man kann hier also auch eine komplexere Bedingung angeben, die irgendwann
falsch wird, und so die Schleife abbrechen.
break
-Anweisungen sind jedoch flexibler, da sie die
Schleife an einer beliebigen Stelle im Körper abbrechen können und nicht nur
am Anfang. Im Prinzip können daher alle while
-Schleifen
mit while True:
beginnen.
Weiterführende Lektüre
- Komplexe CLIs mit mehreren Argumenten und Optionen lassen sich komfortabel mit dem Modul
argparse
erstellen.