Kommandolinjeargumenter i Python

Oversikt

Med Python som et veldig populært programmeringsspråk, i tillegg til å ha støtte for de fleste operativsystemer og mange biblioteker som gjør argumentbehandling av kommandolinje enkelt – har det blitt mye brukt til å lage kommandolinjeverktøy for mange formål. Disse verktøyene kan variere fra enkle CLI-apper til de som er mer komplekse, som AWS' awscli verktøyet.

Komplekse verktøy som dette styres vanligvis av brukeren via kommandolinjeargumenter, som lar brukeren bruke spesifikke kommandoer, angi alternativer og mer. For eksempel kan disse alternativene fortelle verktøyet å sende ut tilleggsinformasjon, lese data fra en spesifisert kilde eller sende utdata til et bestemt sted.

Generelt sendes argumenter til CLI-verktøy forskjellig, avhengig av operativsystemet ditt:

  • Unix-lignende: - etterfulgt av et brev, som -heller -- etterfulgt av et ord, som --help
  • Windows: / etterfulgt av enten en bokstav eller et ord, som /help

Disse forskjellige tilnærmingene eksisterer på grunn av historiske årsaker. Mange programmer på Unix-lignende systemer støtter både enkelt- og dobbelstreknotasjon. Enkeltstreknotasjonen brukes for det meste med alternativer med én bokstav, mens doble bindestreker gir en mer lesbar alternativliste, noe som er spesielt nyttig for komplekse alternativer som må være mer eksplisitte.

Merknader: I denne artikkelen vil vi kun fokusere på det Unix-lignende formatet til - og --.

Husk at både navnet og betydningen av et argument er spesifikke for et program - det er ingen generell definisjon, annet enn noen få vanlige konvensjoner som --help for mer informasjon om bruken av verktøyet. Som utvikler av et Python-skript vil du bestemme hvilke argumenter du skal gi til den som ringer og hva de gjør. Dette krever skikkelig evaluering.

Etter hvert som listen over tilgjengelige argumenter vokser, vil koden din bli mer kompleks når du prøver å analysere dem nøyaktig. Heldigvis er det i Python en rekke biblioteker tilgjengelig for å hjelpe deg med dette. Vi vil dekke noen av de vanligste løsningene, som spenner fra "gjør-det-selv" med sys.argv, til "gjort-for-deg"-tilnærmingen med argparse.

Håndtere kommandolinjeargumenter med Python

Python 3+ og økosystemet rundt støtter en rekke forskjellige måter å håndtere kommandolinjeargumenter på. Det er mange biblioteker som fasiliterer å analysere kommandolinjeargumenter.

Den innebygde måten er å bruke sys modul. Når det gjelder navn og bruk, er det direkte knyttet til C-biblioteket (libc).

Den andre måten er getopt modul, som håndterer både korte og lange alternativer, inkludert evaluering av parameterverdiene.

De argparse-modul, som er avledet fra optparse modul (tilgjengelig opp til Python 2.7).

De docopt modul, som er tilgjengelig på GitHub, tillater også den samme funksjonaliteten.

Nylig, den absl biblioteket har også fått fart, som et middel til å erstatte optparse og getopt().

Hver av disse måtene har sine fordeler og ulemper, så det er verdt å vurdere hver for å se hvilken som passer dine behov best.

sys-modulen

Dette er en grunnleggende modul som har blitt sendt med Python fra de første dagene. Det tar en veldig lik tilnærming til C-biblioteket ved å bruke argc/argv for å få tilgang til argumentene. De sys-modul implementerer kommandolinjeargumentene i en enkel listestruktur med navn sys.argv.

Hvert listeelement representerer et enkelt argument. Det første elementet i listen, sys.argv[0], er navnet på Python-skriptet. Resten av listeelementene, sys.argv[1] til sys.argv[n], er kommandolinjeargumentene 2 til n.

Som avgrensning mellom argumentene brukes et mellomrom. Argumentverdier som inneholder et mellomrom må være omgitt av anførselstegn for å bli korrekt analysert av sys.

Tilsvarer argc er bare antall elementer i listen. For å få denne verdien, bruk Python len() operatør. Vi viser dette i et kodeeksempel senere.

Skriver ut det første CLI-argumentet

I dette første eksemplet vil skriptet vårt bestemme måten det ble kalt på. Denne informasjonen holdes i det første kommandolinjeargumentet, indeksert med 0. Koden nedenfor viser hvordan du får navnet på Python-skriptet ditt:

import sys

print("The script has the name %s" % (sys.argv[0])

Lagre denne koden i en fil med navnet arguments-program-name.py, og kall det deretter som vist nedenfor. Utdataene er som følger og inneholder filnavnet, inkludert hele banen:

$ python arguments-program-name.py
The script has the name arguments-program-name.py
$ python /home/user/arguments-program-name.py
The script has the name /home/user/arguments-program-name.py

Som du kan se fra den andre samtalen ovenfor, får vi ikke bare navnet på Python-filen, men også hele banen som ble brukt til å kalle den.

Å telle antall argumenter

I dette andre eksemplet teller vi ganske enkelt antall kommandolinjeargumenter ved å bruke den innebygde len() metoden. sys.argv er listen som vi må undersøke. I koden nedenfor får vi antall argumenter og trekker deretter 1 fordi ett av disse argumentene (dvs. det første) alltid er satt som navnet på filen, noe som ikke alltid er nyttig for oss. Dermed er det faktiske antallet argumenter som sendes av brukeren len(sys.argv) - 1:

import sys


arguments = len(sys.argv) - 1
print ("The script is called with %i arguments" % (arguments))

Lagre og navngi denne filen arguments-count.py. Noen eksempler på å kalle dette skriptet er vist nedenfor. Dette inkluderer tre forskjellige scenarier:

  • Et anrop uten flere kommandolinjeargumenter
  • En oppfordring med to argumenter
  • Et kall med to argumenter, der det andre er en anførselsstreng som inneholder et mellomrom
$ python arguments-count.py
The script is called with 0 arguments
$ python arguments-count.py --help me
The script is called with 2 arguments
$ python arguments-count.py --option "long string"
The script is called with 2 arguments
Iterasjon gjennom argumenter

Vårt tredje eksempel gir ut hvert enkelt argument som sendes til Python-skriptet, bortsett fra selve programnavnet. Derfor går vi gjennom kommandolinjeargumentene som starter med sekund listeelement. Husk at dette er indeks 1 siden lister er 0-baserte i Python:

import sys


arguments = len(sys.argv) - 1


position = 1
while (arguments >= position):
    print ("Parameter %i: %s" % (position, sys.argv[position]))
    position = position + 1

Nedenfor kaller vi koden vår, som ble lagret i filen arguments-output.py. Som gjort med vårt forrige eksempel, illustrerer utdataene tre forskjellige samtaler:

  • En samtale uten argumenter
  • En oppfordring med to argumenter
  • Et kall med to argumenter, der det andre argumentet er en anførselsstreng som inneholder et mellomrom
$ python arguments-output.py
$ python arguments-output.py --help me
Parameter 1: --help
Parameter 2: me
$ python arguments-output.py --option "long string"
Parameter 1: --option
Parameter 2: long string

Husk at poenget med å vise det siterte strengeksemplet er at parametere vanligvis er avgrenset med et mellomrom, med mindre de er omgitt av sitater.

Abseil flagg (absl)

Abseils Flags-bibliotek er ment å bringe kommandolinjeargumenter til produksjon, med distribuerte kommandolinjeargumenter. Når en modul bruker kommandolinjeflagg, og importeres til en annen modul – den andre modulen importerer også flaggene, og kan behandle dem ved å videresende dem til den importerte modulen.

Dette gjør komplekse kommandolinjeargumenter som deles mellom moduler enklere og mindre detaljerte.

I tillegg lar biblioteket deg definere standardverdier, beskrivelser av og datatype for argumentene, slik at ytterligere kontroller og konverteringer ikke er nødvendige.

from absl import flags
import sys


flags.DEFINE_string('name', 'User', 'The name of the user.')


FLAGS = flags.FLAGS
FLAGS(sys.argv)

print(f"Hello {FLAGS.name}!")

De støttede datatypene er:

  • DEFINE_integer()
  • DEFINE_string()
  • DEFINE_bool()
  • DEFINE_enum()
  • DEFINE_list()
  • DEFINE_float()

I tillegg til DEFINE_multi_integer(), DEFINE_multi_string() og DEFINE_multi_enum() for multi-argument input. I tillegg løping --help, --helpfull, etc. skrive ut eksisterende flagg og deres beskrivelser, i forskjellige formater.

Sjekk ut vår praktiske, praktiske guide for å lære Git, med beste praksis, bransjeaksepterte standarder og inkludert jukseark. Slutt å google Git-kommandoer og faktisk lære den!

Biblioteket lar deg også definere valideringer – både når det gjelder rekkevidde, for eksempel heltallsbaserte verdier som har en upper_bound or lower_bound det er akseptabelt, og kjører vilkårlige metoder for å se etter verdier:

def validate_name(value):
    return len(value) > 15

flags.register_validator('name',
                         validate_name,
                         message='Name is over 15 characters long.',
                         flag_values=FLAGS)

Samle disse til et konkret eksempel:

from absl import flags
import sys

flags.DEFINE_string('name', 'User', 'The name of the user.')
flags.DEFINE_integer('tasks', 0, 'The number of tasks a user has.', lower_bound=0)

FLAGS = flags.FLAGS
FLAGS(sys.argv)

print(f"{FLAGS.name} has {FLAGS.tasks} tasks to work on.")
$ python flags.py --name=John --tasks=5
John has 5 tasks to work on.
$ python flags.py --name=John --tasks=-1

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_flag.py", line 180, in _parse
    return self.parser.parse(argument)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_argument_parser.py", line 168, in parse
    raise ValueError('%s is not %s' % (val, self.syntactic_help))
ValueError: -1 is not a non-negative integer
...

Argparse-modulen

De argparse-modul har vært tilgjengelig siden Python 3.2, og en forbedring av optparse modul som eksisterer opp til Python 2.7. Python-dokumentasjonen inneholder en API-beskrivelse og en veiledning som dekker alle metodene i detalj.

Modulen tilbyr et kommandolinjegrensesnitt med en standardisert utgang, mens de to førstnevnte løsningene legger mye av arbeidet i dine hender. argparse tillater verifisering av faste og valgfrie argumenter, med navnekontroll som enten kort eller lang stil. Som et standard valgfritt argument inkluderer det -h, sammen med den lange versjonen --help. Dette argumentet er ledsaget av en standard hjelpemelding som beskriver de aksepterte argumentene.

Koden nedenfor viser parserinitialiseringen, og utdataene nedenfor som viser det grunnleggende anropet, etterfulgt av hjelpemeldingen. I motsetning til Python-kallene vi brukte i de forrige eksemplene, husk å bruke Python 3 med disse eksemplene:


import argparse


parser = argparse.ArgumentParser()
parser.parse_args()
$ python3 arguments-argparse-basic.py 
$ python3 arguments-argparse-basic.py -h
usage: arguments-argparse-basic.py [-h]

optional arguments:
  -h, --help  show this help message and exit
$ python3 arguments-argparse-basic.py --verbose
usage: arguments-argparse-basic.py [-h]
arguments-argparse-basic.py: error: unrecognized arguments: --verbose

I neste trinn vil vi legge til en tilpasset beskrivelse i hjelpemeldingen for brukerne våre. Initialisering av parseren på denne måten tillater en ekstra tekst. Koden nedenfor lagrer beskrivelsen i text variabel, som er eksplisitt gitt til argparse klasse som description parameter. Ved å ringe denne koden nedenfor kan du se hvordan utgangen ser ut:


import argparse


text = 'This is a test program. It demonstrates how to use the argparse module with a program description.'


parser = argparse.ArgumentParser(description=text)
parser.parse_args()
$ python3 arguments-argparse-description.py --help
usage: arguments-argparse-description.py [-h]

This is a test program. It demonstrates how to use the argparse module with a
program description.

optional arguments:
  -h, --help  show this help message and exit

Som det siste trinnet vil vi legge til et valgfritt argument kalt -V, som har et tilsvarende lang stilargument kalt --version. For å gjøre det bruker vi metoden add_argument() som vi kaller med tre parametere (vises for --version, bare):

  • Navnet på parameteren: --version
  • Hjelpeteksten for parameteren: help="show program version"
  • Handling (uten tilleggsverdi): action="store_true"

Kildekoden for det vises nedenfor. Lese argumentene inn i variabelen kalt args gjøres via parse_args() metoden fra parser gjenstand. Merk at du sender inn både den korte og den lange versjonen i en samtale. Til slutt sjekker du om attributtene args.V or args.version er satt og sender ut versjonsmeldingen:


import argparse


parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="show program version", action="store_true")


args = parser.parse_args()


if args.version:
    print("This is myprogram version 0.1")
$ python3 arguments-argparse-optional.py -V
This is myprogram version 0.1
$ python3 arguments-argparse-optional.py --version
This is myprogram version 0.1

De --version argumentet krever ikke at en verdi oppgis på kommandolinjen. Derfor setter vi handlingsargumentet til "store_true". I andre tilfeller kan det hende du trenger en ekstra tilordnet verdi, for eksempel hvis du spesifiserer et visst volum, høyde eller bredde. Dette er vist i neste eksempel. Vær oppmerksom på at alle argumentene tolkes som strenger som standard:


import argparse


parser = argparse.ArgumentParser()


parser.add_argument("--width", "-w", help="set output width")


args = parser.parse_args()


if args.width:
    print("Set output width to %s" % args.width)

Her viser vi hva som skjer når du sender inn ulike argumentverdier. Dette inkluderer både den korte og den lange versjonen, samt hjelpemeldingen:

$ python3 arguments-argparse-optional2.py -w 10
Set output width to 10
$ python3 arguments-argparse-optional2.py --width 10
Set output width to 10
$ python3 arguments-argparse-optional2.py -h
usage: arguments-argparse-optional2.py [-h] [--width WIDTH]

optional arguments:
  -h, --help            show this help message and exit
  --width WIDTH, -w WIDTH
                        set output width

Getopt-modulen

Som du kanskje har lagt merke til før sys modulen deler kommandolinjestrengen kun i enkeltfasetter. Pytonen getopt-modul går litt lenger og utvider separasjonen av inngangsstrengen ved parametervalidering. Basert på getopt C-funksjon, den tillater både korte og lange alternativer, inkludert en verditilordning.

I praksis krever det sys modul for å behandle inndata på riktig måte. For å gjøre det må både sys modulen og getopt modulen må lastes inn på forhånd. Deretter fjerner vi det første listeelementet fra listen over inngangsparametere (se koden nedenfor), og lagrer den gjenværende listen med kommandolinjeargumenter i variabelen kalt argument_list:


import getopt, sys


full_cmd_arguments = sys.argv


argument_list = full_cmd_arguments[1:]

print argument_list

Argumentene i argument_list kan nå analyseres ved hjelp av getopts() metode. Men før vi gjør det, må vi fortelle det getopts() om hvilke parametere som er gyldige. De er definert slik:

short_options = "ho:v"
long_options = ["help", "output=", "verbose"]

Dette betyr at disse argumentene er de vi anser for å være gyldige, sammen med litt ekstra info:

------------------------------------------
long argument   short argument  with value
------------------------------------------
--help           -h              no
--output         -o              yes
--verbose        -v              no
------------------------------------------

Du har kanskje lagt merke til at o kort alternativ ble fulgt av et kolon, :. Dette forteller getopt at dette alternativet skal tildeles en verdi.

Dette lar oss nå behandle en liste med argumenter. De getopt() metoden krever at tre parametere konfigureres – listen over faktiske argumenter fra argv, samt både de gyldige korte og lange alternativene (vist i forrige kodebit).

Selve metodekallet holdes i en try-catch-statement for å dekke feil under evalueringen. Et unntak oppstår hvis det oppdages et argument som ikke er en del av listen som definert tidligere. Python-skriptet vil skrive ut feilmeldingen til skjermen og avslutte med feilkode 2:

try:
    arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
    
    print (str(err))
    sys.exit(2)

Til slutt lagres argumentene med de tilsvarende verdiene i de to navngitte variablene arguments og values. Nå kan du enkelt evaluere disse variablene i koden din. Vi kan bruke en for-løkke for å iterere gjennom listen over gjenkjente argumenter, en oppføring etter den neste.


for current_argument, current_value in arguments:
    if current_argument in ("-v", "--verbose"):
        print ("Enabling verbose mode")
    elif current_argument in ("-h", "--help"):
        print ("Displaying help")
    elif current_argument in ("-o", "--output"):
        print (("Enabling special output mode (%s)") % (current_value))

Nedenfor kan du se resultatet fra utføring av denne koden. Vi viser hvordan programmet reagerer med både gyldige og ugyldige programargumenter:

$ python arguments-getopt.py -h
Displaying help
$ python arguments-getopt.py --help
Displaying help
$ python arguments-getopt.py --output=green --help -v
Enabling special output mode (green)
Displaying help
Enabling verbose mode
$ python arguments-getopt.py -verbose
option -e not recognized

Den siste samtalen til programmet vårt kan virke litt forvirrende i begynnelsen. For å forstå det, må du vite at alternativene for stenografi (noen ganger også kalt flagg) kan brukes sammen med en enkelt strek. Dette gjør at verktøyet lettere kan godta mange alternativer. For eksempel å ringe python arguments-getopt.py -vh er det samme som å ringe python arguments-getopt.py -v -h. Så i den siste samtalen ovenfor getopt modulen trodde brukeren prøvde å passere -e som et alternativ, som er ugyldig.

konklusjonen

I denne artikkelen viste vi mange forskjellige metoder for å hente kommandolinjeargumenter i Python, inkludert bruk sys, getoptog argparse. Disse modulene varierer i funksjonalitet, noen gir mye mer enn andre. sys er fullt fleksibel, mens begge deler getoptog argparse krever litt struktur. Derimot dekker de det meste av det komplekse arbeidet som sys overlater opp til deg. Etter å ha jobbet gjennom eksemplene som er gitt, bør du være i stand til å finne ut hvilken modul som passer ditt prosjekt best.

I denne artikkelen snakket vi ikke om andre løsninger som docopts modul, vi nevnte det nettopp. Denne modulen følger en helt annen tilnærming, og vil bli forklart i detalj i en av de neste artiklene.

Referanser

Tidstempel:

Mer fra Stackabuse