Den Zielnamen kann man weg lassen, der wird durch "--operation" ja bereits vorgegeben. Dafür sollte man "plus" als Default-Wert angeben, damit man in dem Wörterbuch nicht unter `None` noch mal eine Funktion wiederholen muss.
Wenn man bei der Option die möglichen Auswahlmöglichkeiten als `choices` angibt, braucht man nicht mehr selber zu prüfen ob der angegebene Operation bekannt/erlaubt ist. Und die Fehlermeldung erwähnt dann auch gleich welche Operationen erlaubt/bekannt sind:
Code: Alles auswählen
$ ./forum41.py -o potenz 3 5
Usage: forum41.py [options]
forum41.py: error: option -o: invalid choice: 'potenz' (choose from 'plus', 'minus', 'mal', 'geteilt')
Zwischenstand:
Code: Alles auswählen
#!/usr/bin/env python3
from operator import add, mul, sub, truediv
from optparse import OptionParser
#
# Erster Eintrag ist die Default-Operation.
#
OPERATION_TO_FUNCTION = {
"plus": add,
"minus": sub,
"mal": mul,
"geteilt": truediv,
}
def main():
operations = list(OPERATION_TO_FUNCTION.keys())
parser = OptionParser()
parser.add_option(
"-o", "--operation", choices=operations, default=operations[0]
)
options, arguments = parser.parse_args()
if len(arguments) != 2:
parser.error("Es werden exakt zwei Argumente erwartet")
print(
"Ergebnis:",
OPERATION_TO_FUNCTION[options.operation](
float(arguments[0]), float(arguments[1])
),
)
if __name__ == "__main__":
main()
Nun ist aber `optparse` nicht mehr so wirklich stand der Dinge, sondern nur noch für Spezialfälle und zum Beispiel als Basis für die `click`-Bibliothek. Aktuell ist `argparse` in der Standardbibliothek. Dort gibt man auch die Argumente an, damit die auch einen Namen und einen Typ und eine Hilfe haben, wie die Optionen, und damit wird dann auch die Anzahl und der Typ von der Bibliothek geprüft, so dass man das nicht mehr selber machen muss:
Code: Alles auswählen
#!/usr/bin/env python3
from argparse import ArgumentParser
from operator import add, mul, sub, truediv
#
# Erster Eintrag ist die Default-Operation.
#
OPERATION_TO_FUNCTION = {
"plus": add,
"minus": sub,
"mal": mul,
"geteilt": truediv,
}
def main():
operations = list(OPERATION_TO_FUNCTION.keys())
parser = ArgumentParser()
parser.add_argument(
"-o", "--operation", choices=operations, default=operations[0]
)
parser.add_argument("operand_a", type=float)
parser.add_argument("operand_b", type=float)
arguments = parser.parse_args()
print(
"Ergebnis:",
OPERATION_TO_FUNCTION[arguments.operation](
arguments.operand_a, arguments.operand_b
),
)
if __name__ == "__main__":
main()
Die generierte Hilfe kann dadurch auch besser werden als bei `optparse`. Hier die von `optparse`:
Code: Alles auswählen
$ ./forum41.py --help
Usage: forum41.py [options]
Options:
-h, --help show this help message and exit
-o OPERATION, --operation=OPERATION
Im Vergleich dazu die von `argparse` (die zusätzlich im Terminal auch noch bunt ist):
Code: Alles auswählen
$ ./orum42.py --help
usage: forum42.py [-h] [-o {plus,minus,mal,geteilt}] operand_a operand_b
positional arguments:
operand_a
operand_b
options:
-h, --help show this help message and exit
-o, --operation {plus,minus,mal,geteilt}
Und wo ich `click` nun schon erwähnt hatte, hier wie das mit dieser externen Bibliothek aussehen könnte:
Code: Alles auswählen
#!/usr/bin/env python3
from enum import Enum
from operator import add, mul, sub, truediv
import click
class Operation(Enum):
PLUS = add
MINUS = sub
MAL = mul
GETEILT = truediv
@click.command()
@click.option(
"-o",
"--operation",
type=click.Choice(Operation, case_sensitive=False),
default=Operation.PLUS,
)
@click.argument("operand_a", type=float)
@click.argument("operand_b", type=float)
def calculate(operation, operand_a, operand_b):
print("Ergebnis:", operation.value(operand_a, operand_b))
if __name__ == "__main__":
calculate()