Aufwärmen · Aufgabe 1 von 7
Aufwärmen aus der Lektion über Module: Diese Datei wird mit python main.py gestartet. Was gibt sie aus?
print(__name__)// I4.2 · ca. 35 Min. · Aufbau
Nach dieser Lektion machen Sie aus einem Skript ein Kommandozeilenprogramm: Es liest Argumente und Optionen mit argparse, meldet Fehler auf stderr und endet mit dem passenden Exit-Status.
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
print(__name__)Vorhersagen · Aufgabe 2 von 7
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name")
parser.add_argument("--times", type=int, default=1)
args = parser.parse_args(["Ada", "--times", "3"])
print(args.name * args.times)Üben · Aufgabe 3 von 7
parser.add_argument("--verbose", action="____")Üben · Aufgabe 4 von 7
import sys
sys.exit("disk full")Üben · Aufgabe 5 von 7
Denksport · Aufgabe 6 von 7
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--debug", type=bool)
args = parser.parse_args(["--debug", "False"])
print(args.debug)Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
wordcount zählt die Wörter eines Texts, mit einer Option --min-length und einem Schalter -u. Damit Sie mehrere Kommandozeilen auf einmal sehen, ruft demo() main mit Argumentlisten auf und zeigt den Exit-Status; stderr landet ebenfalls in der Ausgabe. Ersetzen Sie auf Ihrem Rechner die demo-Aufrufe durch sys.exit(main()) und starten Sie python main.py "the cat sat" --min-length 3.
main.py
import argparse
import shlex
import sys
from contextlib import redirect_stderr
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="wordcount", description="Count the words in a text.")
parser.add_argument("text", help="the text to count")
parser.add_argument("--min-length", type=int, default=1, help="skip shorter words")
parser.add_argument("-u", "--upper", action="store_true", help="print the words in upper case")
args = parser.parse_args(argv) # None: read sys.argv[1:]
words = [word for word in args.text.split() if len(word) >= args.min_length]
if not words:
print("wordcount: no words left", file=sys.stderr)
return 1
shown = " ".join(words).upper() if args.upper else " ".join(words)
print(f"{len(words)} words: {shown}")
return 0
def demo(argv: list[str]) -> None:
"""Runs main as if typed in a terminal; stderr shows up in the output too."""
print(f"$ python main.py {shlex.join(argv)}".rstrip())
with redirect_stderr(sys.stdout):
try:
status = main(argv)
except SystemExit as stop: # argparse exits on --help and on bad input
status = stop.code if isinstance(stop.code, int) else 1
print("exit status", status)
if __name__ == "__main__":
# On your computer, replace these demos with: sys.exit(main())
demo(["the cat sat on the mat", "--min-length", "3"])
demo(["-u", "hello world"])
demo(["a b", "--min-length", "5"])
demo(["hello", "--min-length", "three"])
demo([])
demo(["--help"])
Ausführen mit
python main.pyAusgabe
$ python main.py 'the cat sat on the mat' --min-length 3
5 words: the cat sat the mat
exit status 0
$ python main.py -u 'hello world'
2 words: HELLO WORLD
exit status 0
$ python main.py 'a b' --min-length 5
wordcount: no words left
exit status 1
$ python main.py hello --min-length three
usage: wordcount [-h] [--min-length MIN_LENGTH] [-u] text
wordcount: error: argument --min-length: invalid int value: 'three'
exit status 2
$ python main.py
usage: wordcount [-h] [--min-length MIN_LENGTH] [-u] text
wordcount: error: the following arguments are required: text
exit status 2
$ python main.py --help
usage: wordcount [-h] [--min-length MIN_LENGTH] [-u] text
Count the words in a text.
positional arguments:
text the text to count
options:
-h, --help show this help message and exit
--min-length MIN_LENGTH
skip shorter words
-u, --upper print the words in upper case
exit status 0Übung 1 von 2
Vervollständigen Sie main(argv) in greet.py (hier main.py). Es nimmt einen Namen, eine Option --times (int, Standard 1) und einen Schalter --shout. Es gibt Hello, <name>! so oft aus, wie --times sagt, mit --shout in Großbuchstaben, und gibt 0 zurück. Ein --times, das keine Zahl ist, muss mit dem Exit-Status 2 von argparse enden. Führen Sie die Tests aus und probieren Sie dann python main.py Ada --times 3 --shout auf Ihrem Rechner (python3 unter macOS und Linux).
Diese Übung braucht Python auf Ihrem Computer (die Browser-Version kann sie nicht ausführen). Dateien und Befehle stehen unten.
parser.add_argument("--times", type=int, default=1) macht args.times zu einem int, der ohne Angabe 1 ist.
action="store_true" macht --shout zum Schalter; prüfen Sie ihn mit if args.shout:.
Bauen Sie die Begrüßung einmal, rufen Sie beim Schreien .upper() auf und geben Sie sie in for _ in range(args.times): aus.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import argparse
import sys
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="greet")
parser.add_argument("name")
parser.add_argument("--times", type=int, default=1)
parser.add_argument("--shout", action="store_true")
args = parser.parse_args(argv)
greeting = f"Hello, {args.name}!"
if args.shout:
greeting = greeting.upper()
for _ in range(args.times):
print(greeting)
return 0
if __name__ == "__main__":
sys.exit(main())
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
import argparse
import sys
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="greet")
parser.add_argument("name")
# Add --times (an int, default 1) and the flag --shout.
args = parser.parse_args(argv)
print(f"Hello, {args.name}!")
return 0
if __name__ == "__main__":
sys.exit(main())
test_main.py
import contextlib
import io
from main import main
def run(argv):
out = io.StringIO()
err = io.StringIO()
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
try:
status = main(argv)
except SystemExit as stop:
status = stop.code
return status, out.getvalue().splitlines(), err.getvalue()
def test_default():
"""Ada allein ergibt eine Begrüßung und Status 0"""
status, lines, err = run(["Ada"])
assert (status, lines) == (0, ["Hello, Ada!"]), f"main(['Ada']) gab {status!r} zurück und {lines!r} aus; stderr: {err!r}"
def test_times():
"""--times 3 gibt die Begrüßung dreimal aus"""
status, lines, err = run(["Ada", "--times", "3"])
assert lines == ["Hello, Ada!"] * 3, f"mit --times 3 gab das Programm {lines!r} aus; stderr: {err!r}"
def test_shout():
"""--shout schreibt groß, vor oder nach dem Namen"""
status, lines, err = run(["--shout", "Bo"])
assert lines == ["HELLO, BO!"], f"mit --shout gab das Programm {lines!r} aus; stderr: {err!r}"
def test_bad_times():
"""--times many endet mit Exit-Status 2"""
status, lines, err = run(["Ada", "--times", "many"])
assert status == 2, f"mit --times many war der Status {status!r}, erwartet 2 (lassen Sie type=int ablehnen)"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenÜbung 2 von 2
main.py bildet den Durchschnitt der Zahlen auf seiner Kommandozeile, mit --max (Standard 100). Korrigieren Sie es: Liegt eine Zahl über dem Maximum, schreiben Sie average: 500.0 is above the maximum 100.0 (mit den echten Werten) nach stderr, nichts nach stdout, und geben 1 zurück. Sonst geben Sie den Durchschnitt mit zwei Nachkommastellen aus und geben 0 zurück. Als Programm gestartet muss der Status die Shell erreichen: Enden Sie mit sys.exit(main()).
Diese Übung braucht Python auf Ihrem Computer (die Browser-Version kann sie nicht ausführen). Dateien und Befehle stehen unten.
print(..., file=sys.stderr) schickt eine Zeile nach stderr statt nach stdout.
Geben Sie direkt nach der Fehlermeldung 1 zurück, damit der Durchschnitt nie ausgegeben wird.
main() gibt den Status zurück, aber erst sys.exit(main()) reicht ihn an die Shell weiter.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
import argparse
import sys
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="average")
parser.add_argument("numbers", nargs="+", type=float)
parser.add_argument("--max", type=float, default=100.0)
args = parser.parse_args(argv)
for number in args.numbers:
if number > args.max:
print(f"average: {number} is above the maximum {args.max}", file=sys.stderr)
return 1
print(f"{sum(args.numbers) / len(args.numbers):.2f}")
return 0
if __name__ == "__main__":
sys.exit(main())
Installieren Sie Python 3.14 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.py
import argparse
import sys
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="average")
parser.add_argument("numbers", nargs="+", type=float)
parser.add_argument("--max", type=float, default=100.0)
args = parser.parse_args(argv)
for number in args.numbers:
if number > args.max:
print(f"average: {number} is above the maximum {args.max}")
print(f"{sum(args.numbers) / len(args.numbers):.2f}")
return 0
if __name__ == "__main__":
main()
test_main.py
import contextlib
import io
import sys
from learnrun import run_main
from main import main
def run(argv):
out = io.StringIO()
err = io.StringIO()
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
try:
status = main(argv)
except SystemExit as stop:
status = stop.code
return status, out.getvalue(), err.getvalue()
def test_average():
"""2, 4 und 9 ergeben 5.00 und Status 0"""
status, out, err = run(["2", "4", "9"])
assert (status, out.strip()) == (0, "5.00"), f"main gab {status!r} zurück und {out!r} aus"
def test_above_max():
"""500 wird auf stderr gemeldet, mit Status 1 und leerem stdout"""
status, out, err = run(["5", "500"])
assert status == 1, f"main gab {status!r} zurück, erwartet 1"
assert out == "", f"stdout sollte leer sein, enthält aber {out!r}"
assert err.strip() == "average: 500.0 is above the maximum 100.0", f"stderr enthält {err!r}"
def test_custom_max():
"""--max 10 weist 11 ab"""
status, out, err = run(["--max", "10", "5", "11"])
assert status == 1, f"mit --max 10 und 11 gab main {status!r} zurück, erwartet 1"
def test_not_a_number():
"""Ein Wort statt einer Zahl endet mit Status 2"""
status, out, err = run(["five"])
assert status == 2, f"für five war der Status {status!r}, erwartet 2"
def test_status_reaches_the_shell():
"""Als Programm endet python main.py 5 500 mit Status 1"""
saved = sys.argv
sys.argv = ["main.py", "5", "500"]
code = 0
try:
with contextlib.redirect_stderr(io.StringIO()):
run_main()
except SystemExit as stop:
code = stop.code
finally:
sys.argv = saved
assert code == 1, f"das Programm endete mit Status {code!r}, erwartet 1: rufen Sie sys.exit(main()) auf"
Unter macOS und Linux tippen Sie python3, wo in diesen Befehlen python steht, wie in der ersten Lektion.
Programm ausführen:
python main.pyPrüfungen ausführen (learnrun.py muss im selben Ordner liegen):
python learnrun.py testlearnrun.py herunterladenimport argparse
parser = argparse.ArgumentParser()
parser.add_argument("count")
args = parser.parse_args(["3"])
print(args.count + 1)
Was Python ausgibt
TypeError: can only concatenate str (not "int") to strWarum, und die Lösung
Jedes Kommandozeilenargument kommt als String an, und argparse lässt es ohne type dabei. Schreiben Sie add_argument("count", type=int). Dann wandelt argparse den Wert um und weist etwas wie three mit einer klaren Meldung und Exit-Status 2 ab.
import argparse
parser = argparse.ArgumentParser(prog="wordcount")
parser.add_argument("--min-length", type=int, default=1)
args = parser.parse_args(["--min-length", "3"])
print(args.min-length)
Was Python ausgibt
AttributeError: 'Namespace' object has no attribute 'min'Warum, und die Lösung
args.min-length liest Python als args.min minus length. argparse macht aus Bindestrichen im Optionsnamen Unterstriche, der Wert steht also in args.min_length.
import argparse
parser = argparse.ArgumentParser(prog="greet")
parser.add_argument("name")
args = parser.parse_args([])
print("Hello,", args.name)
Was Python ausgibt
greet: error: the following arguments are required: nameWarum, und die Lösung
Ein Positionsargument muss angegeben werden. argparse schreibt die Kurzhilfe und diesen Fehler nach stderr und endet mit Status 2; print wird nie erreicht. Soll es optional sein, machen Sie eine Option mit Standardwert daraus, etwa add_argument("--name", default="world").
Python im Browser: Pyodide 314.0.7, MPL-2.0. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.