argparse

  • Författare
  • Meddelande
Användarvisningsbild

annettekusma

sql-guru

  • Inlägg: 102
  • Blev medlem: 11 aug 2017, 10:16
  • Ort: Eskilstuna

argparse

Inlägg14 okt 2017, 21:32

Nu har jag författat och förkastat flera frågor om argparse de senaste veckorna. Varje gång har jag under resans gång kommit på en lösning eller rättare sagt, fått igenom det jag ville på något sätt som jag dock inte alltid har begripit fullt ut.

En aspekt jag inte har koll på ännu är ordningen. Om man har en option -a/--amount, och man ger en destination, en default, en constant och nargs='?', så bör parsern skicka default-värdet om man inte alls anger -a, konstant-värdet om man bara anger -a och det av användaren givna värdet om man anger -a plus värde.

Varianten med bara -a som ska ge ett konstantvärde fungerar inte om man anger denna option före ett annat argument (t.ex. input-filen). Alltså:

main.py letters -a är OK
main.py -a letters är inte OK, argparse klagar på att 'letters' inte är en integer.

Borde inte en professionell parser-modul känna igen 'letters' som ett eget argument snarare än att klaga? Annars kunde jag ju lika gärna jobba med sys.argv direkt istället.

Definierar man denna option i huvudparsern kan man placera den var man vill om man alltså inte luras med kringliggande argument, men defninierar man denna option i en subparser så fungerar den bara om man lägger den efter 'kommandot'. Jag skulle vilja tala om för parsern att option -a ska fungera för vissa kommandon, men ska ge felmeddelande för andra, i övrigt ska det inte spela nån roll om man placerar den före eller efter kommandot. Bortsett från det sista kravet, så blir ju lösningen att defniniera det för de subparsrar där det ska gälla, men det blir ju ett dubbelarbete vilket är ett fult ord inom programmeringsvärlden har jag förstått.

Och det är ungefär här som det brukar snurra till i huvudet, jag brukar gå till dokumentationen och läsa två timmar, lära mig en del orelaterade saker, få till en fix på mitt problem och begripa ingenting.

Så, vad har proffsen att säga om ordningen av kommandona? Jag antar att exempelvis bashkommandon har vissa mönster (hur vet användaren om hen ska skriva '-a 7' eller '-a=7'?) och att argparse immiterar dem. Jag hade ju också för mig att man kan slå ihop flaggorna ibland, dvs ist f att skriva -l -a -t så räcker det att skriva -lat.
Användarvisningsbild

Lew

dbwebb

  • Inlägg: 406
  • Blev medlem: 05 sep 2012, 13:42
  • Ort: Karlskrona

Re: argparse

Inlägg16 okt 2017, 10:34

annettekusma skrev:Om man har en option -a/--amount, och man ger en destination, en default, en constant och nargs='?', så bör parsern skicka default-värdet om man inte alls anger -a, konstant-värdet om man bara anger -a och det av användaren givna värdet om man anger -a plus värde.


Det är precis så det fungerar. Det är dock inte riktigt så magiskt att den känner av om det är ett kommando du skickar in, utan det tolkas som ett värde till ditt option.

Givet koden:
Kod: Markera allt
parser.add_argument("-a", "--amount", nargs="?", default=7, const=1)


Blir utfallet följande:

Kod: Markera allt
$ python3 main.py
>>> 'args': {'amount': 7}

option -a är inte inskickat, default används.

Kod: Markera allt
$ python3 main.py -a
>>> 'args': {'amount': 1}

option -a skickas med utan värde, const används.

Kod: Markera allt
$ python3 main.py -a 42
>>> 'args': {'amount': 42}

option -a 42 skickas med (även -a=42 fungerar)

Kod: Markera allt
$ python3 main.py -a letters
>>> 'args': {'amount': letters}


annettekusma skrev:Jag skulle vilja tala om för parsern att option -a ska fungera för vissa kommandon, men ska ge felmeddelande för andra

Ett sätt är att lösa detta är att bara använda "amount" där du vill använda det.

main.py:
Kod: Markera allt
...
if command == "letters":
        # använd amount här
        print("command:", command)
        print("amount:", options["args"]["amount"])
...


Kan användas på följande sätt:
Kod: Markera allt
$ python3 main.py letters
>>> command: letters
>>> amount: 7


Kod: Markera allt
$ python3 main.py -a 5 letters
>>> command: letters
>>> amount: 5


annettekusma skrev:i övrigt ska det inte spela nån roll om man placerar den före eller efter kommandot.


Det kan man inte riktigt kringå på ett smidigt sätt. Kör man python3 main.py -a letters kommer letters tolkas som värde till amount. Det är bättre att använda default-värdet och inte skicka med -a alls i de fallen.

Vad det gäller ordningen bör den vara: [options/flags] [command or file] då options/flaggor gäller för kommandona.

anettekusma skrev:hur vet användaren om hen ska skriva '-a 7' eller '-a=7'?

I argparse tolkas det automatiskt, se: https://dbwebb.se/kunskap/argparse#korbart-program

annettekusma skrev:Jag hade ju också för mig att man kan slå ihop flaggorna ibland, dvs ist f att skriva -l -a -t så räcker det att skriva -lat.

Det går alldeles utmärkt:

Kod: Markera allt
parser.add_argument('-a', action='store_true', default=False)
parser.add_argument('-b', action='store_true', default=False)


Det kan du köra med:
Kod: Markera allt
$ python3 main.py -ab
>>> 'args': {'a': True, 'b': True}

https://stackoverflow.com/questions/21286203/python-argparse-allow-combined-flags
When in doubt, use brute force.

Vilka är online

Användare som besöker denna kategori: Inga registrerade användare och 12 gäster