Opdrachtregelargumenten in Python

Overzicht

Omdat Python een zeer populaire programmeertaal is en ondersteuning biedt voor de meeste besturingssystemen en vele bibliotheken die de verwerking van argumentatie op de opdrachtregel eenvoudig maken, wordt het op grote schaal gebruikt om opdrachtregelprogramma's voor vele doeleinden te maken. Deze tools kunnen variรซren van eenvoudige CLI-apps tot complexere apps, zoals die van AWS. awscli gereedschap.

Complexe tools zoals deze worden doorgaans door de gebruiker bestuurd via opdrachtregelargumenten, waarmee de gebruiker specifieke opdrachten kan gebruiken, opties kan instellen en meer. Deze opties kunnen de tool bijvoorbeeld vertellen om aanvullende informatie uit te voeren, gegevens uit een opgegeven bron te lezen of uitvoer naar een bepaalde locatie te sturen.

Over het algemeen worden argumenten op verschillende manieren doorgegeven aan CLI-tools, afhankelijk van uw besturingssysteem:

  • Unix-achtig: - gevolgd door een brief, bijv -hof -- gevolgd door een woord, zoals --help
  • Windows: / gevolgd door een letter of een woord, zoals /help

Deze verschillende benaderingen bestaan โ€‹โ€‹โ€‹โ€‹om historische redenen. Veel programma's op Unix-achtige systemen ondersteunen zowel de enkele als de dubbele streepjesnotatie. De notatie met รฉรฉn streepje wordt meestal gebruikt bij opties met รฉรฉn letter, terwijl dubbele streepjes een beter leesbare lijst met opties weergeven, wat vooral handig is voor complexe opties die explicieter moeten zijn.

Note: In dit artikel concentreren we ons uitsluitend op het Unix-achtige formaat van - en --.

Houd er rekening mee dat zowel de naam als de betekenis van een argument specifiek zijn voor een programma โ€“ er is geen algemene definitie, behalve een paar algemene conventies zoals --help voor meer informatie over het gebruik van de tool. Als ontwikkelaar van een Python-script bepaal jij welke argumenten je aan de beller meegeeft en wat deze doen. Dit vergt een goede evaluatie.

Naarmate uw lijst met beschikbare argumenten groeit, wordt uw code complexer in het proberen deze nauwkeurig te ontleden. Gelukkig zijn er in Python een aantal bibliotheken beschikbaar die je hierbij kunnen helpen. We bespreken enkele van de meest voorkomende oplossingen, variรซrend van โ€œdoe-het-zelfโ€ tot sys.argv, naar de โ€œdone-for-youโ€-aanpak met argparse.

Omgaan met opdrachtregelargumenten met Python

Python 3+ en het omringende ecosysteem ondersteunen een aantal verschillende manieren om opdrachtregelargumenten af โ€‹โ€‹te handelen. Er zijn veel bibliotheken die het ontleden van opdrachtregelargumenten vergemakkelijken.

De ingebouwde manier is om de sys module. In termen van namen en het gebruik ervan heeft het rechtstreeks betrekking op de C-bibliotheek (libc).

De tweede manier is de getopt module, die zowel korte als lange opties afhandelt, inclusief de evaluatie van de parameterwaarden.

De argparse-module, die is afgeleid van de optparse module (beschikbaar tot Python 2.7).

De docopt module, dat is beschikbaar op GitHub, biedt ook dezelfde functionaliteit.

Onlangs heeft de absl bibliotheek wint ook aan kracht, als middel om te vervangen optparse en getopt().

Elk van deze manieren heeft zijn voor- en nadelen, dus het is de moeite waard om ze allemaal te evalueren om te zien welke het beste bij uw behoeften past.

De sys-module

Dit is een basismodule die vanaf het begin bij Python werd geleverd. Het vergt een zeer vergelijkbare aanpak als de C-bibliotheek die gebruikt argc/argv om toegang te krijgen tot de argumenten. De sys-module implementeert de opdrachtregelargumenten in een eenvoudige lijststructuur met de naam sys.argv.

Elk lijstelement vertegenwoordigt een enkel argument. Het eerste item in de lijst, sys.argv[0], is de naam van het Python-script. De rest van de lijstelementen, sys.argv[1] naar sys.argv[n], zijn de opdrachtregelargumenten 2 tot en met n.

Als scheidingsteken tussen de argumenten wordt een spatie gebruikt. Argumentwaarden die een spatie bevatten, moeten tussen aanhalingstekens worden geplaatst om correct te kunnen worden geparseerd sys.

het equivalent van argc is slechts het aantal elementen in de lijst. Om deze waarde te verkrijgen, gebruikt u Python len() exploitant. We zullen dit later in een codevoorbeeld laten zien.

Het eerste CLI-argument afdrukken

In dit eerste voorbeeld bepaalt ons script de manier waarop het werd aangeroepen. Deze informatie wordt bewaard in het eerste opdrachtregelargument, geรฏndexeerd met 0. De onderstaande code laat zien hoe u de naam van uw Python-script krijgt:

import sys

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

Sla deze code op in een bestand met de naam arguments-program-name.pyen noem het vervolgens zoals hieronder weergegeven. De uitvoer is als volgt en bevat de bestandsnaam, inclusief het volledige pad:

$ 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

Zoals je kunt zien in de tweede oproep hierboven, krijgen we niet alleen de naam van het Python-bestand, maar ook het volledige pad waarmee het is aangeroepen.

Het aantal argumenten tellen

In dit tweede voorbeeld tellen we eenvoudigweg het aantal opdrachtregelargumenten met behulp van het ingebouwde len() methode. sys.argv is de lijst die we moeten onderzoeken. In de onderstaande code krijgen we het aantal argumenten en trekken we er vervolgens 1 van af, omdat een van die argumenten (dwz de eerste) altijd wordt ingesteld als de naam van het bestand, wat niet altijd nuttig voor ons is. Het werkelijke aantal argumenten dat door de gebruiker wordt doorgegeven, is dus gelijk len(sys.argv) - 1:

import sys


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

Sla dit bestand op en noem het argumenten-count.py. Hieronder vindt u enkele voorbeelden van het aanroepen van dit script. Dit omvat drie verschillende scenario's:

  • Een oproep zonder verdere opdrachtregelargumenten
  • Een oproep met twee argumenten
  • Een aanroep met twee argumenten, waarbij de tweede een tekenreeks tussen aanhalingstekens is die een spatie bevat
$ 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
Itereren door argumenten

Ons derde voorbeeld voert elk afzonderlijk argument uit dat naar het Python-script wordt verzonden, behalve de programmanaam zelf. Daarom doorlopen we de opdrachtregelargumenten, beginnend met de tweede lijstelement. Bedenk dat dit index 1 is, aangezien lijsten in Python op 0 zijn gebaseerd:

import sys


arguments = len(sys.argv) - 1


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

Hieronder noemen we onze code, die is opgeslagen in het bestand argumenten-output.py. Net als in ons vorige voorbeeld illustreert de uitvoer drie verschillende oproepen:

  • Een telefoontje zonder enige argumenten
  • Een oproep met twee argumenten
  • Een aanroep met twee argumenten, waarbij het tweede argument een tekenreeks tussen aanhalingstekens is die een spatie bevat
$ 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

Houd er rekening mee dat het punt van het tonen van het voorbeeld van de aangehaalde tekenreeks is dat parameters gewoonlijk worden gescheiden door een spatie. tenzij ze zijn omgeven door aanhalingstekens.

Abseilvlaggen (absl)

De Flags-bibliotheek van Abseil is bedoeld om opdrachtregelargumenten in productie te brengen, met gedistribueerde opdrachtregelargumenten. Wanneer een module opdrachtregelvlaggen gebruikt en in een andere module wordt geรฏmporteerd โ€“ de andere module importeert ook de vlaggenen kan ze verwerken door ze door te sturen naar de geรฏmporteerde module.

Dit maakt complexe opdrachtregelargumenten die tussen modules worden gedeeld eenvoudiger en minder uitgebreid.

Bovendien kunt u in de bibliotheek de standaardwaarden, beschrijvingen en gegevenstypes van de argumenten definiรซren, zodat aanvullende controles en conversies niet nodig zijn.

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 ondersteunde gegevenstypen zijn:

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

Evenals DEFINE_multi_integer(), DEFINE_multi_string() en DEFINE_multi_enum() voor invoer met meerdere argumenten. Daarnaast hardlopen --help, --helpfull, enz. druk de bestaande vlaggen en hun beschrijvingen af, in verschillende formaten.

Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!

Met de bibliotheek kunt u ook validaties definiรซren, zowel in termen van bereik, zoals op gehele getallen gebaseerde waarden met een upper_bound or lower_bound dat is acceptabel, en het uitvoeren van willekeurige methoden om op waarden te controleren:

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

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

Deze verzameld in een concreet voorbeeld:

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
...

De argparse-module

De argparse-module is beschikbaar sinds Python 3.2, en een verbetering van de optparse module die bestaat tot Python 2.7. De Python-documentatie bevat een API-beschrijving en een tutorial waarin alle methoden in detail worden behandeld.

De module biedt een opdrachtregelinterface met een gestandaardiseerde uitvoer, terwijl de eerste twee oplossingen veel van het werk aan u overlaten. argparse maakt de verificatie van vaste en optionele argumenten mogelijk, met naamcontrole in korte of lange stijl. Als standaard optioneel argument bevat het -h, samen met de lange versie --help. Dit argument gaat vergezeld van een standaard helpbericht waarin de geaccepteerde argumenten worden beschreven.

De onderstaande code toont de initialisatie van de parser en de onderstaande uitvoer toont de basisoproep, gevolgd door het Help-bericht. In tegenstelling tot de Python-aanroepen die we in de vorige voorbeelden gebruikten, moet je er rekening mee houden dat je Python 3 met deze voorbeelden gebruikt:


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

In de volgende stap voegen we een aangepaste beschrijving toe aan het helpbericht voor onze gebruikers. Door de parser op deze manier te initialiseren, is een extra tekst mogelijk. De onderstaande code slaat de beschrijving op in het text variabele, die expliciet wordt gegeven aan de argparse klasse als de description parameter. Als u deze code hieronder aanroept, kunt u zien hoe de uitvoer eruit ziet:


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

Als laatste stap zullen we een optioneel argument toevoegen met de naam -V, waarvoor een bijbehorend lang stijlargument wordt genoemd --version. Hiervoor gebruiken we de methode add_argument() die we aanroepen met drie parameters (weergegeven voor --version, alleen):

  • De naam van de parameter: --version
  • De helptekst voor de parameter: help="show program version"
  • Actie (zonder toegevoegde waarde): action="store_true"

De broncode daarvoor wordt hieronder weergegeven. Het inlezen van de argumenten in de aangeroepen variabele args gebeurt via de parse_args() methode uit de parser voorwerp. Let op: u dient zowel de korte als de lange versie in รฉรฉn call in. Tenslotte controleer je of de attributen args.V or args.version zijn ingesteld en geven het versiebericht weer:


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 argument vereist geen waarde die op de opdrachtregel moet worden opgegeven. Daarom hebben we het actieargument ingesteld op "store_true". In andere gevallen heeft u mogelijk een extra toegewezen waarde nodig, bijvoorbeeld als u een bepaald volume, hoogte of breedte opgeeft. Dit wordt getoond in het volgende voorbeeld. Houd er standaard rekening mee dat alle argumenten worden geรฏnterpreteerd als tekenreeksen:


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)

Hier laten we zien wat er gebeurt als u verschillende argumentwaarden indient. Dit omvat zowel de korte als de lange versie, evenals het helpbericht:

$ 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

De getopt-module

Zoals je misschien al eerder hebt gemerkt, is de sys module splitst de opdrachtregelreeks alleen in afzonderlijke facetten. De Python getopt-module gaat een beetje verder en breidt de scheiding van de invoerreeks uit door parametervalidatie. Gebaseerd op de getopt C-functie, het maakt zowel korte als lange opties mogelijk, inclusief een waardetoewijzing.

In de praktijk vereist het de sys module om invoergegevens goed te verwerken. Om dit te doen, moeten zowel de sys module en de getopt module moet vooraf worden geladen. Vervolgens verwijderen we uit de lijst met invoerparameters het eerste lijstelement (zie de onderstaande code) en slaan we de resterende lijst met opdrachtregelargumenten op in de variabele genaamd argument_list:


import getopt, sys


full_cmd_arguments = sys.argv


argument_list = full_cmd_arguments[1:]

print argument_list

De argumenten binnen argument_list kan nu worden geparseerd met behulp van de getopts() methode. Maar voordat we dat doen, moeten we het vertellen getopts() over welke parameters geldig zijn. Ze worden als volgt gedefinieerd:

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

Dit betekent dat we deze argumenten als geldig beschouwen, samen met wat extra informatie:

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

Het is je misschien opgevallen dat de o korte optie werd voorafgegaan door een dubbele punt, :. Dit vertelt getopt dat deze optie een waarde moet krijgen.

Hierdoor kunnen we nu een lijst met argumenten verwerken. De getopt() methode vereist dat drie parameters worden geconfigureerd โ€“ de lijst met feitelijke argumenten uit argv, evenals zowel de geldige korte als lange opties (weergegeven in het vorige codefragment).

De methodeaanroep zelf wordt bewaard in een try-catch-statement om fouten tijdens de evaluatie te dekken. Er wordt een uitzondering gemaakt als er een argument wordt ontdekt dat geen deel uitmaakt van de lijst zoals eerder gedefinieerd. Het Python-script drukt de foutmelding op het scherm af en sluit af met foutcode 2:

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

Ten slotte worden de argumenten met de bijbehorende waarden opgeslagen in de twee genoemde variabelen arguments en values. Nu kunt u deze variabelen eenvoudig in uw code evalueren. Wij kunnen gebruik maken van een for-loop om de lijst met herkende argumenten te doorlopen, het ene item na het andere.


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))

Hieronder ziet u de uitvoer van het uitvoeren van deze code. We laten zien hoe het programma reageert met zowel geldige als ongeldige programmaargumenten:

$ 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

De laatste oproep aan ons programma lijkt in eerste instantie misschien wat verwarrend. Om het te begrijpen, moet u weten dat de steno-opties (soms ook vlaggen genoemd) samen met een enkel streepje kunnen worden gebruikt. Hierdoor kan uw gereedschap veel opties gemakkelijker accepteren. Bellen bijvoorbeeld python arguments-getopt.py -vh is hetzelfde als bellen python arguments-getopt.py -v -h. Dus in de laatste oproep hierboven, de getopt module dacht dat de gebruiker probeerde te slagen -e als een optie, die ongeldig is.

Conclusie

In dit artikel hebben we veel verschillende methoden laten zien voor het ophalen van opdrachtregelargumenten in Python, inclusief het gebruik van sys, getopt en argparse. Deze modules variรซren in functionaliteit, sommige bieden veel meer dan andere. sys is volledig flexibel, terwijl beide getopten argparse enige structuur nodig. Daarentegen bestrijken ze het grootste deel van het complexe werk dat dat met zich meebrengt sys laat het aan jou over. Nadat u de gegeven voorbeelden heeft doorgenomen, kunt u bepalen welke module het beste bij uw project past.

In dit artikel hebben we het niet gehad over andere oplossingen zoals de docopts module, we hebben het zojuist genoemd. Deze module volgt een totaal andere aanpak en zal in een van de volgende artikelen gedetailleerd worden uitgelegd.

Referenties

Tijdstempel:

Meer van Stapelmisbruik