Argparse-Tutorial¶
Dieses Tutorial soll eine sanfte Einführung in argparse sein, das empfohlene Modul zum Zerlegen der Befehlszeile in der Python-Standardbibliothek.
Bemerkung
Die Standardbibliothek enthält zwei weitere Bibliotheken, die unmittelbar mit der Verarbeitung von Befehlszeilenparametern zu tun haben: das tieferliegende Modul optparse (das für eine gegebene Anwendung möglicherweise mehr Code zur Einrichtung braucht, einer Anwendung aber auch Verhalten erlaubt, das argparse nicht unterstützt) und das sehr tiefliegende getopt (das ausdrücklich als Gegenstück zur Funktionsfamilie getopt() dient, die C-Programmierern zur Verfügung steht). Keines dieser beiden Module wird in dieser Anleitung unmittelbar behandelt, aber viele der Kernkonzepte von argparse stammen ursprünglich aus optparse. Manche Teile dieses Tutorials sind daher auch für Nutzer von optparse von Belang.
Begriffe¶
Zeigen wir anhand des Befehls ls, welche Art von Funktionalität wir in diesem einführenden Tutorial erkunden werden:
$ ls
cpython devguide prog.py pypy rm-unused-function.patch
$ ls pypy
ctypes_configure demo dotviewer include lib_pypy lib-python ...
$ ls -l
total 20
drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython
drwxr-xr-x 4 wena wena 4096 Feb 8 12:04 devguide
-rwxr-xr-x 1 wena wena 535 Feb 19 00:05 prog.py
drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy
-rw-r--r-- 1 wena wena 741 Feb 18 01:01 rm-unused-function.patch
$ ls --help
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.
...
Ein paar Begriffe, die wir aus den vier Befehlen lernen können:
Der Befehl ls ist nützlich, auch wenn er ganz ohne Optionen ausgeführt wird. Standardmäßig zeigt er den Inhalt des aktuellen Verzeichnisses an.
Wollen wir mehr als das, was er standardmäßig bietet, sagen wir ihm ein bisschen mehr. In diesem Fall wollen wir, dass er ein anderes Verzeichnis anzeigt,
pypy. Wir haben damit das angegeben, was als positionelles Argument bekannt ist. Es heißt so, weil das Programm allein daran, wo der Wert auf der Befehlszeile steht, erkennen soll, was es damit tun muss. Deutlicher wird dieser Begriff bei einem Befehl wie cp, dessen grundlegendste Verwendungcp SRC DESTist. Die erste Position ist das, was kopiert werden soll, und die zweite Position ist das Ziel, wohin es kopiert werden soll.Nehmen wir nun an, wir wollen das Verhalten des Programms ändern. In unserem Beispiel zeigen wir für jede Datei mehr Informationen an, anstatt nur die Dateinamen. Das
-lin diesem Fall ist als optionales Argument bekannt.Das ist ein Ausschnitt des Hilfetexts. Er ist sehr nützlich, weil du auf ein Programm stoßen kannst, das du noch nie verwendet hast, und allein durch das Lesen seines Hilfetexts herausfinden kannst, wie es funktioniert.
Die Grundlagen¶
Beginnen wir mit einem ganz einfachen Beispiel, das (fast) nichts tut:
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
Folgendes ist das Ergebnis, wenn man den Code ausführt:
$ python prog.py
$ python prog.py --help
usage: prog.py [-h]
options:
-h, --help show this help message and exit
$ python prog.py --verbose
usage: prog.py [-h]
prog.py: error: unrecognized arguments: --verbose
$ python prog.py foo
usage: prog.py [-h]
prog.py: error: unrecognized arguments: foo
Das passiert hier:
Das Skript ohne Optionen auszuführen zeigt nichts auf der Standardausgabe. Nicht so nützlich.
Das zweite beginnt, die Nützlichkeit des Moduls
argparsezu zeigen. Wir haben so gut wie nichts getan, bekommen aber schon eine schöne Hilfemeldung.Die Option
--help, die sich auch zu-hverkürzen lässt, ist die einzige Option, die wir umsonst bekommen (also ohne sie angeben zu müssen). Alles andere anzugeben führt zu einem Fehler. Aber selbst dann bekommen wir eine nützliche Verwendungsmeldung – ebenfalls umsonst.
Positionelle Argumente einführen¶
Ein Beispiel:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)
Und der Code ausgeführt:
$ python prog.py
usage: prog.py [-h] echo
prog.py: error: the following arguments are required: echo
$ python prog.py --help
usage: prog.py [-h] echo
positional arguments:
echo
options:
-h, --help show this help message and exit
$ python prog.py foo
foo
Das passiert hier:
Wir haben die Methode
add_argument()ergänzt, mit der wir angeben, welche Befehlszeilenoptionen das Programm annehmen soll. In diesem Fall habe ich sieechogenannt, damit es zu ihrer Aufgabe passt.Unser Programm aufzurufen erfordert jetzt, dass wir eine Option angeben.
Die Methode
parse_args()gibt tatsächlich einige Daten aus den angegebenen Optionen zurück, in diesem Fallecho.Die Variable ist eine Art „Magie“, die
argparseumsonst erledigt (du musst also nicht angeben, in welcher Variablen dieser Wert gespeichert wird). Dir wird auch auffallen, dass ihr Name mit dem Zeichenkettenargument übereinstimmt, das der Methode übergeben wurde:echo.
Beachte aber, dass die Hilfeausgabe zwar schön aussieht, derzeit aber nicht so hilfreich ist, wie sie sein könnte. Wir sehen zum Beispiel, dass wir echo als positionelles Argument bekommen haben, wissen aber nicht, was es tut – außer durch Raten oder durch Lesen des Quellcodes. Machen wir es also etwas nützlicher:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print(args.echo)
Und wir bekommen:
$ python prog.py -h
usage: prog.py [-h] echo
positional arguments:
echo echo the string you use here
options:
-h, --help show this help message and exit
Wie wäre es nun mit etwas noch Nützlicherem:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)
Folgendes ist das Ergebnis, wenn man den Code ausführt:
$ python prog.py 4
Traceback (most recent call last):
File "prog.py", line 5, in <module>
print(args.square**2)
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
Das lief nicht so gut. Der Grund: argparse behandelt die Optionen, die wir ihm geben, als Zeichenketten, sofern wir nichts anderes sagen. Sagen wir argparse also, es soll diese Eingabe als Ganzzahl behandeln:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help="display a square of a given number",
type=int)
args = parser.parse_args()
print(args.square**2)
Folgendes ist das Ergebnis, wenn man den Code ausführt:
$ python prog.py 4
16
$ python prog.py four
usage: prog.py [-h] square
prog.py: error: argument square: invalid int value: 'four'
Das lief gut. Das Programm bricht jetzt sogar hilfreich bei unzulässiger Eingabe ab, bevor es weitermacht.
Optionale Argumente einführen¶
Bisher haben wir mit positionellen Argumenten gespielt. Sehen wir uns an, wie man optionale hinzufügt:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="increase output verbosity")
args = parser.parse_args()
if args.verbosity:
print("verbosity turned on")
Und die Ausgabe:
$ python prog.py --verbosity 1
verbosity turned on
$ python prog.py
$ python prog.py --help
usage: prog.py [-h] [--verbosity VERBOSITY]
options:
-h, --help show this help message and exit
--verbosity VERBOSITY
increase output verbosity
$ python prog.py --verbosity
usage: prog.py [-h] [--verbosity VERBOSITY]
prog.py: error: argument --verbosity: expected one argument
Das passiert hier:
Das Programm ist so geschrieben, dass es etwas anzeigt, wenn
--verbosityangegeben ist, und nichts, wenn nicht.Um zu zeigen, dass die Option tatsächlich optional ist: Es gibt keinen Fehler, wenn man das Programm ohne sie ausführt. Beachte, dass die betroffene Variable – in diesem Fall
args.verbosity– standardmäßig den WertNonebekommt, wenn ein optionales Argument nicht verwendet wird. Deshalb scheitert sie an der Wahrheitsprüfung derif-Anweisung.Die Hilfemeldung sieht etwas anders aus.
Bei Verwendung der Option
--verbositymuss man außerdem einen Wert angeben, irgendeinen Wert.
Das obige Beispiel nimmt für --verbosity beliebige ganzzahlige Werte an, aber für unser einfaches Programm sind tatsächlich nur zwei Werte nützlich: True oder False. Ändern wir den Code entsprechend:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbose", help="increase output verbosity",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("verbosity turned on")
Und die Ausgabe:
$ python prog.py --verbose
verbosity turned on
$ python prog.py --verbose 1
usage: prog.py [-h] [--verbose]
prog.py: error: unrecognized arguments: 1
$ python prog.py --help
usage: prog.py [-h] [--verbose]
options:
-h, --help show this help message and exit
--verbose increase output verbosity
Das passiert hier:
Die Option ist jetzt mehr ein Schalter als etwas, das einen Wert braucht. Wir haben sogar den Namen der Option geändert, damit er zu dieser Idee passt. Beachte, dass wir nun ein neues Schlüsselwort angeben,
action, und ihm den Wert"store_true"geben. Das bedeutet: Ist die Option angegeben, weiseargs.verboseden WertTruezu. Sie nicht anzugeben bedeutetFalse.Es beschwert sich, wenn du einen Wert angibst – ganz im Sinne dessen, was Schalter eigentlich sind.
Beachte den anderen Hilfetext.
Kurze Optionen¶
Wenn du mit der Verwendung der Befehlszeile vertraut bist, wird dir auffallen, dass ich das Thema der kurzen Fassungen der Optionen noch nicht angesprochen habe. Es ist recht einfach:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", help="increase output verbosity",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("verbosity turned on")
Und los geht’s:
$ python prog.py -v
verbosity turned on
$ python prog.py --help
usage: prog.py [-h] [-v]
options:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
Beachte, dass die neue Fähigkeit sich auch im Hilfetext widerspiegelt.
Positionelle und optionale Argumente verbinden¶
Unser Programm wird immer komplexer:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbose", action="store_true",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbose:
print(f"the square of {args.square} equals {answer}")
else:
print(answer)
Und nun die Ausgabe:
$ python prog.py
usage: prog.py [-h] [-v] square
prog.py: error: the following arguments are required: square
$ python prog.py 4
16
$ python prog.py 4 --verbose
the square of 4 equals 16
$ python prog.py --verbose 4
the square of 4 equals 16
Wir haben ein positionelles Argument zurückgebracht, daher die Beschwerde.
Beachte, dass die Reihenfolge keine Rolle spielt.
Wie wäre es, wenn wir unserem Programm die Fähigkeit zu mehreren Werten für die Ausführlichkeit zurückgeben und sie tatsächlich nutzen:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int,
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Und die Ausgabe:
$ python prog.py 4
16
$ python prog.py 4 -v
usage: prog.py [-h] [-v VERBOSITY] square
prog.py: error: argument -v/--verbosity: expected one argument
$ python prog.py 4 -v 1
4^2 == 16
$ python prog.py 4 -v 2
the square of 4 equals 16
$ python prog.py 4 -v 3
16
Die sehen alle gut aus – außer dem letzten, der einen Fehler in unserem Programm offenlegt. Beheben wir ihn, indem wir die Werte einschränken, die die Option --verbosity annehmen kann:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Und die Ausgabe:
$ python prog.py 4 -v 3
usage: prog.py [-h] [-v {0,1,2}] square
prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, 1, 2)
$ python prog.py 4 -h
usage: prog.py [-h] [-v {0,1,2}] square
positional arguments:
square display a square of a given number
options:
-h, --help show this help message and exit
-v, --verbosity {0,1,2}
increase output verbosity
Beachte, dass sich die Änderung sowohl in der Fehlermeldung als auch in der Hilfezeichenkette widerspiegelt.
Nehmen wir nun einen anderen Ansatz für das Spiel mit der Ausführlichkeit, der recht verbreitet ist. Er entspricht auch der Art, wie die CPython-Programmdatei ihr eigenes Argument für die Ausführlichkeit behandelt (sieh dir die Ausgabe von python --help an):
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display the square of a given number")
parser.add_argument("-v", "--verbosity", action="count",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Wir haben eine weitere Aktion eingeführt, „count“, um die Anzahl der Vorkommen bestimmter Optionen zu zählen.
$ python prog.py 4
16
$ python prog.py 4 -v
4^2 == 16
$ python prog.py 4 -vv
the square of 4 equals 16
$ python prog.py 4 --verbosity --verbosity
the square of 4 equals 16
$ python prog.py 4 -v 1
usage: prog.py [-h] [-v] square
prog.py: error: unrecognized arguments: 1
$ python prog.py 4 -h
usage: prog.py [-h] [-v] square
positional arguments:
square display a square of a given number
options:
-h, --help show this help message and exit
-v, --verbosity increase output verbosity
$ python prog.py 4 -vvv
16
Ja, es ist jetzt – wie in der vorigen Fassung unseres Skripts – mehr ein Schalter (ähnlich wie
action="store_true"). Das sollte die Beschwerde erklären.Es verhält sich auch ähnlich wie die Aktion „store_true“.
Und hier eine Vorführung dessen, was die Aktion „count“ liefert. Diese Art der Verwendung hast du wahrscheinlich schon gesehen.
Und wenn du den Schalter
-vnicht angibst, gilt dieser Schalter als mit dem WertNonebelegt.Wie zu erwarten, bekommen wir dieselbe Ausgabe, wenn wir die lange Form des Schalters angeben.
Unsere Hilfeausgabe ist leider nicht sehr aufschlussreich über die neue Fähigkeit, die unser Skript erworben hat, aber das lässt sich immer beheben, indem wir die Dokumentation unseres Skripts verbessern (etwa über das Schlüsselwortargument
help).Diese letzte Ausgabe legt einen Fehler in unserem Programm offen.
Beheben wir ihn:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", action="count",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
# bugfix: replace == with >=
if args.verbosity >= 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Und das ergibt Folgendes:
$ python prog.py 4 -vvv
the square of 4 equals 16
$ python prog.py 4 -vvvv
the square of 4 equals 16
$ python prog.py 4
Traceback (most recent call last):
File "prog.py", line 11, in <module>
if args.verbosity >= 2:
TypeError: '>=' not supported between instances of 'NoneType' and 'int'
Die erste Ausgabe lief gut und behebt den Fehler, den wir vorher hatten. Wir wollen nämlich, dass jeder Wert >= 2 so ausführlich wie möglich ist.
Die dritte Ausgabe nicht so gut.
Beheben wir diesen Fehler:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", action="count", default=0,
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity >= 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Wir haben gerade noch ein Schlüsselwort eingeführt: default. Wir haben es auf 0 gesetzt, damit es mit den anderen int-Werten vergleichbar ist. Denk daran, dass ein optionales Argument standardmäßig den Wert None bekommt, wenn es nicht angegeben wird, und dass dieser sich nicht mit einem int-Wert vergleichen lässt (daher die TypeError-Ausnahme).
Und:
$ python prog.py 4
16
Mit dem, was wir bisher gelernt haben, kommst du schon recht weit – und wir haben nur an der Oberfläche gekratzt. Das Modul argparse ist sehr mächtig, und wir erkunden noch ein wenig mehr davon, bevor wir dieses Tutorial beenden.
Etwas fortgeschrittener¶
Was, wenn wir unser kleines Programm erweitern wollten, damit es andere Potenzen berechnet und nicht nur Quadrate:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
parser.add_argument("-v", "--verbosity", action="count", default=0)
args = parser.parse_args()
answer = args.x**args.y
if args.verbosity >= 2:
print(f"{args.x} to the power {args.y} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.x}^{args.y} == {answer}")
else:
print(answer)
Ausgabe:
$ python prog.py
usage: prog.py [-h] [-v] x y
prog.py: error: the following arguments are required: x, y
$ python prog.py -h
usage: prog.py [-h] [-v] x y
positional arguments:
x the base
y the exponent
options:
-h, --help show this help message and exit
-v, --verbosity
$ python prog.py 4 2 -v
4^2 == 16
Beachte, dass wir die Stufe der Ausführlichkeit bisher verwendet haben, um den angezeigten Text zu ändern. Das folgende Beispiel verwendet die Stufe der Ausführlichkeit stattdessen, um mehr Text anzuzeigen:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
parser.add_argument("-v", "--verbosity", action="count", default=0)
args = parser.parse_args()
answer = args.x**args.y
if args.verbosity >= 2:
print(f"Running '{__file__}'")
if args.verbosity >= 1:
print(f"{args.x}^{args.y} == ", end="")
print(answer)
Ausgabe:
$ python prog.py 4 2
16
$ python prog.py 4 2 -v
4^2 == 16
$ python prog.py 4 2 -vv
Running 'prog.py'
4^2 == 16
Uneindeutige Argumente angeben¶
Wenn es uneindeutig ist, ob ein Argument positionell ist oder zu einem Argument gehört, lässt sich -- verwenden, um parse_args() zu sagen, dass alles danach ein positionelles Argument ist:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-n', nargs='+')
>>> parser.add_argument('args', nargs='*')
>>> # ambiguous, so parse_args assumes it's an option
>>> parser.parse_args(['-f'])
usage: PROG [-h] [-n N [N ...]] [args ...]
PROG: error: unrecognized arguments: -f
>>> parser.parse_args(['--', '-f'])
Namespace(args=['-f'], n=None)
>>> # ambiguous, so the -n option greedily accepts arguments
>>> parser.parse_args(['-n', '1', '2', '3'])
Namespace(args=[], n=['1', '2', '3'])
>>> parser.parse_args(['-n', '1', '--', '2', '3'])
Namespace(args=['2', '3'], n=['1'])
Widersprüchliche Optionen¶
Bisher haben wir mit zwei Methoden einer argparse.ArgumentParser-Instanz gearbeitet. Führen wir eine dritte ein: add_mutually_exclusive_group(). Damit können wir Optionen angeben, die einander widersprechen. Ändern wir außerdem den Rest des Programms, damit die neue Funktionalität mehr Sinn ergibt: Wir führen die Option --quiet ein, die das Gegenteil von --verbose sein wird:
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y
if args.quiet:
print(answer)
elif args.verbose:
print(f"{args.x} to the power {args.y} equals {answer}")
else:
print(f"{args.x}^{args.y} == {answer}")
Unser Programm ist jetzt einfacher, und wir haben zur Vorführung etwas Funktionalität eingebüßt. Wie auch immer, hier die Ausgabe:
$ python prog.py 4 2
4^2 == 16
$ python prog.py 4 2 -q
16
$ python prog.py 4 2 -v
4 to the power 2 equals 16
$ python prog.py 4 2 -vq
usage: prog.py [-h] [-v | -q] x y
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
$ python prog.py 4 2 -v --quiet
usage: prog.py [-h] [-v | -q] x y
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
Das sollte leicht nachzuvollziehen sein. Ich habe diese letzte Ausgabe ergänzt, damit du siehst, welche Art von Spielraum du bekommst – also lange mit kurzen Formen von Optionen zu mischen.
Bevor wir schließen: Du willst deinen Benutzern wahrscheinlich den Hauptzweck deines Programms mitteilen, falls sie ihn nicht kennen:
import argparse
parser = argparse.ArgumentParser(description="calculate X to the power of Y")
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y
if args.quiet:
print(answer)
elif args.verbose:
print(f"{args.x} to the power {args.y} equals {answer}")
else:
print(f"{args.x}^{args.y} == {answer}")
Beachte den kleinen Unterschied im Verwendungstext. Beachte das [-v | -q], das uns sagt, dass wir entweder -v oder -q verwenden können, aber nicht beides gleichzeitig:
$ python prog.py --help
usage: prog.py [-h] [-v | -q] x y
calculate X to the power of Y
positional arguments:
x the base
y the exponent
options:
-h, --help show this help message and exit
-v, --verbose
-q, --quiet
Wie man die Ausgabe von argparse übersetzt¶
Die Ausgabe des Moduls argparse – etwa sein Hilfetext und seine Fehlermeldungen – ist über das Modul gettext vollständig übersetzbar gemacht. Damit können Anwendungen die von argparse erzeugten Meldungen mühelos lokalisieren. Siehe auch Internationalizing your programs and modules.
In dieser Ausgabe von argparse zum Beispiel:
$ python prog.py --help
usage: prog.py [-h] [-v | -q] x y
calculate X to the power of Y
positional arguments:
x the base
y the exponent
options:
-h, --help show this help message and exit
-v, --verbose
-q, --quiet
Die Zeichenketten usage:, positional arguments:, options: und show this help message and exit sind alle übersetzbar.
Um diese Zeichenketten zu übersetzen, müssen sie zuerst in eine .po-Datei herausgezogen werden. Führe dazu zum Beispiel mit Babel diesen Befehl aus:
$ pybabel extract -o messages.po /usr/lib/python3.12/argparse.py
Dieser Befehl zieht alle übersetzbaren Zeichenketten aus dem Modul argparse heraus und gibt sie in eine Datei namens messages.po aus. Der Befehl geht davon aus, dass deine Python-Installation in /usr/lib liegt.
Wo das Modul argparse auf deinem System liegt, findest du mit diesem Skript heraus:
import argparse
print(argparse.__file__)
Sobald die Meldungen in der .po-Datei übersetzt und die Übersetzungen über gettext installiert sind, kann argparse die übersetzten Meldungen anzeigen.
Um deine eigenen Zeichenketten in der Ausgabe von argparse zu übersetzen, verwende gettext.
Eigene Typumwandler¶
Das Modul argparse erlaubt es dir, für deine Befehlszeilenargumente eigene Typumwandler anzugeben. Damit kannst du die Benutzereingabe verändern, bevor sie im argparse.Namespace gespeichert wird. Das kann nützlich sein, wenn du die Eingabe vorverarbeiten musst, bevor sie in deinem Programm verwendet wird.
Als eigenen Typumwandler kannst du jedes aufrufbare Objekt verwenden, das ein einzelnes Zeichenkettenargument (den Argumentwert) nimmt und den umgewandelten Wert zurückgibt. Musst du allerdings komplexere Fälle behandeln, kannst du stattdessen über den Parameter action eine eigene Aktionsklasse verwenden.
Nehmen wir zum Beispiel an, du willst Argumente mit unterschiedlichen Präfixen behandeln und entsprechend verarbeiten:
import argparse
parser = argparse.ArgumentParser(prefix_chars='-+')
parser.add_argument('-a', metavar='<value>', action='append',
type=lambda x: ('-', x))
parser.add_argument('+a', metavar='<value>', action='append',
type=lambda x: ('+', x))
args = parser.parse_args()
print(args)
Ausgabe:
$ python prog.py -a value1 +a value2
Namespace(a=[('-', 'value1'), ('+', 'value2')])
In diesem Beispiel haben wir:
einen Parser mit eigenen Präfixzeichen über den Parameter
prefix_charserzeugt.zwei Argumente definiert,
-aund+a, die über den Parametertypeeigene Typumwandler nutzen, um den Wert zusammen mit dem Präfix in einem Tupel zu speichern.
Ohne die eigenen Typumwandler hätten die Argumente -a und +a als dasselbe Argument behandelt, was unerwünscht gewesen wäre. Mit eigenen Typumwandlern konnten wir die beiden Argumente unterscheiden.
Fazit¶
Das Modul argparse bietet viel mehr als hier gezeigt. Seine Dokumentation ist recht detailliert und ausführlich und voller Beispiele. Nachdem du dieses Tutorial durchgearbeitet hast, solltest du sie mühelos verdauen können, ohne dich überfordert zu fühlen.