(gelöst)Optparse richtig anwenden?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Schaf220
User
Beiträge: 113
Registriert: Montag 11. August 2008, 16:00
Wohnort: Bremen
Kontaktdaten:

Hallo liebe Community,
ich komme gerade nicht weiter mit dem Modul Optparse.
Ich habe mir da mal ein Beispielskript herruntergeladen um es zu testen,
doch ich bekomme immer den Fehler aus der else Anweisung, wenn
ich es starte("Es werden exakt zwei Argumente erwartet").
So sieht das Skript jetzt aus:

Code: Alles auswählen

from optparse import OptionParser
parser = OptionParser()
parser.add_option("-o", "--operation", dest="operation")
(optionen, args) = parser.parse_args()
if len(args) != 2:
    parser.error("Es werden exakt zwei Argumente erwartet")
calc = {
       "plus" : lambda a, b: a + b,
       "minus" : lambda a, b: a - b,
       "mal" : lambda a, b: a * b,
       "geteilt" : lambda a, b: a / b,
       None : lambda a, b: a + b
       }
op = optionen.operation
if op in calc:
    print "Ergebnis:", calc[op](float(args[0]), float(args[1]))
else:
    parser.error("%s ist keine Operation" % op)
Was muss ich noch hinzufügen oder verbessern, das ich nicht immer
die Fehlermeldung bekomme, sondern mit der Eingabe der Kommandozeilenschaltern beginnen kann?
So soll es später aufgerufen werden:
calc.py -o plus 7 5
calc.py -o minus 13 29
calc.py -o mal 4 11
calc.py -o geteilt 3 2
Zuletzt geändert von Schaf220 am Dienstag 19. August 2008, 17:53, insgesamt 1-mal geändert.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Schaf220 hat geschrieben: So soll es später aufgerufen werden:
calc.py -o plus 7 5
calc.py -o minus 13 29
calc.py -o mal 4 11
calc.py -o geteilt 3 2
Was heisst spaeter? Du musst es schon jetzt so aufrufen. Bei mir klappt das.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
Schaf220
User
Beiträge: 113
Registriert: Montag 11. August 2008, 16:00
Wohnort: Bremen
Kontaktdaten:

Wenn ich das Skript so starte wie es jetzt ist, dann bekomme ich
sofort die Fehlermeldung! Das Programm beendet sich dann sofort.
Benutzeravatar
snafu
User
Beiträge: 7003
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Klappt bei mir einwandfrei:

Code: Alles auswählen

sebastian@hardy ~> python calc.py -o plus 7 5
Ergebnis: 12.0
sebastian@hardy ~> python calc.py -o minus 13 29
Ergebnis: -16.0
sebastian@hardy ~> python calc.py -o mal 4 11
Ergebnis: 44.0
sebastian@hardy ~> python calc.py -o geteilt 3 2
Ergebnis: 1.5
Benutzeravatar
Schaf220
User
Beiträge: 113
Registriert: Montag 11. August 2008, 16:00
Wohnort: Bremen
Kontaktdaten:

Habt ihr den Code genau so wie er daist oder noch was dazu gefügt?
Bei mir kommt nämlich sofort die Fehlermeldung ich komme erst gar nicht zum eingeben =(
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Schaf220 hat geschrieben: Bei mir kommt nämlich sofort die Fehlermeldung ich komme erst gar nicht zum eingeben =(
Ach die meinst Du ... na dann ist ja alles klar ;-)

SCNR
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Schaf220 hat geschrieben:Habt ihr den Code genau so wie er daist oder noch was dazu gefügt?
Bei mir kommt nämlich sofort die Fehlermeldung ich komme erst gar nicht zum eingeben =(
:?: Du darfst erst Enter druecken, nachdem die komplette Zeile mit den ganzen Parametern eingegeben wurde... Nicht das Programm ausfuehren und dann die Parameter eingeben wollen.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Hyperion hat geschrieben:
Schaf220 hat geschrieben: Bei mir kommt nämlich sofort die Fehlermeldung ich komme erst gar nicht zum eingeben =(
Ach die meinst Du ... na dann ist ja alles klar ;-)

SCNR
Der Punkt ist, wenn du nicht beschreibst was passiert, kann man dir hier nicht helfen ... Kristallkugeln gehn so leicht kaputt :/ Und teuer sind die auch :O
Benutzeravatar
Schaf220
User
Beiträge: 113
Registriert: Montag 11. August 2008, 16:00
Wohnort: Bremen
Kontaktdaten:

hmm ok soweit so gut das hab ich verstanden is mir grad klar geworden,
das alles gemeinsam auf zu rufen ist ja auch nur logisch =)
Jetzt tut sich folgendes Problem auf die Konsole meckert jetzt rumm das der Befehl python nicht erkannt wird obwohl ich das Verzeichnis "C:\Python25"
in die Umgebungsvariablen zu Path hinzu gefügt habe.
Was muss ich noch einstellen unter Vista 64 Bit?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Liegt denn die python.exe da auch drin?
Benutzeravatar
Schaf220
User
Beiträge: 113
Registriert: Montag 11. August 2008, 16:00
Wohnort: Bremen
Kontaktdaten:

So vielen vielen Dank an alle!
Jetzt geht alles in Path war vor dem "C:\Python 25" ein "%",
das habe ich eben entfernt und jetzt geht es wieder.=)
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Code: Alles auswählen

import operator as op

calc = {
       "plus" : op.add
       "minus" : lambda a, b : a -b 
       "mal" : op.mul
       "geteilt" : op.div
       None : op.add
       }
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

audax, magst du ``operator.sub`` nicht?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Habs übersehen, hab gerade ne Soße am kochen :D
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Made my day! :D
Benutzeravatar
__blackjack__
User
Beiträge: 14439
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

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()
“Design patterns are kind of like sarcasm: hard to use well, not always appropriate,
and disgustingly bad when applied to problems they are not meant to solve.” — ajones in c.l.python
imonbln
User
Beiträge: 216
Registriert: Freitag 3. Dezember 2021, 17:07

Der Thread ist mittlerweile alt genug, dass er wählen könnte. Bist du sicher, dass es sich noch lohnt, diese Leiche zu exhumieren?
Benutzeravatar
__blackjack__
User
Beiträge: 14439
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@imonbln: Da ja sonst nicht viel los ist.

Warum sollte es sich nicht lohnen alten Code mal anzuschauen, und den mal zu überarbeiten, mit den Möglichkeiten die man mittlerweile hat. Damit die LLMs weniger veraltetes lernen. 🙃
“Design patterns are kind of like sarcasm: hard to use well, not always appropriate,
and disgustingly bad when applied to problems they are not meant to solve.” — ajones in c.l.python
Benutzeravatar
snafu
User
Beiträge: 7003
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Leichenfledderei aus purer Verzweiflung...? :o
Benutzeravatar
__blackjack__
User
Beiträge: 14439
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Langeweile vielleicht. Verzweifelt war ich noch nicht wirklich. 😉

Noch eine Anmerkung zum Code: Man könnte sich da noch über Fehlerbehandlung Gedanken machen. Zum Beispiel was passieren soll falls der Benutzer `geteilt` und als zweiten Operanden 0 angibt.
“Design patterns are kind of like sarcasm: hard to use well, not always appropriate,
and disgustingly bad when applied to problems they are not meant to solve.” — ajones in c.l.python
Antworten