Ga naar hoofdinhoud

Argumenten parsen in Python

Leer in deze tutorial hoe je één of meer argumenten vanaf de command line of terminal parseert met de modules getopt, sys en argparse.
· 10 min lezen

Verken met AI

Als je een data science- of machine learning-project plant, is het heel gebruikelijk om te beginnen in een Jupyter Notebook. Het biedt interactiviteit met je tools, laat je modules snel draaien, enzovoort. Er zijn veel redenen om Jupyter Notebooks als je belangrijkste wapen te kiezen, zeker voor data science- of machine learning-projecten. Deze tutorial gaat daar echter niet op in.

Stel dat je een Python-script als batchtaak moet draaien voor data-ingestie in je data science-project. Of je moet een Python-script draaien om een machine learning-model op een externe server te deployen. In zulke gevallen is alleen python your_script.py uitvoeren misschien niet genoeg. Je moet mogelijk extra opties of argumenten meegeven naast python your_script.py. Je kent dit gebruik van extra argumenten wellicht al van het uitvoeren van commando’s (zoals ps, ls, enz.) in een Linux-terminal.

In deze tutorial leer je hoe je extra argumenten en opties parseert vanaf de command line die samen met een Python-script worden doorgegeven. Hier is de inhoudsopgave voor vandaag:

  • Een basisintroductie tot argument parsing
  • Argument parsing in Python
    • Met sys.argv
    • Met getopt
    • Met argparse

Let op: deze tutorial gaat uit van basiskennis van Python.

Wat is argument parsing?

Als je Linux gebruikt, weet je dit vast al. Om een overzicht te krijgen van de bestanden en mappen in een bepaalde directory, gebruik je vaak het commando ls. Een typisch resultaat van ls ziet er zo uit:

command

Maar je kunt veel opties aan ls meegeven, -l bijvoorbeeld. Zo ziet die output eruit:

output

Door de -l-optie mee te geven, krijg je meer informatie. Er is hierbij een klein verschil tussen een optie en een argument. Om een bestand of map uit je huidige werkdirectory te verwijderen, gebruik je vaak het commando rm. Stel, je hebt een tekstbestand demo.txt en je voert rm demo.txt uit om het te verwijderen. In dit geval is demo.txt het argument dat je aan het commando rm meegeeft. Als je geen argument aan rm doorgeeft, krijg je een foutmelding zoals deze:

error

Wat is dan het verschil tussen een optie en een argument? Dat is nu wel duidelijk. Opties zijn optioneel om mee te geven, terwijl argumenten (vaak) noodzakelijk zijn. Het is niet nodig om iets aan ls mee te geven om toch output te krijgen.

Als je ls -l of rm demo.txt uitvoert, parseert het besturingssysteem dit op een bepaalde manier onder de motorkap. Dit mechanisme wordt doorgaans gespecificeerd door de ontwikkelaars van het besturingssysteem en staat bekend als parsing.

Als je meer Linux-commando’s en de verschillende opties en argumenten wilt leren kennen, is het boek Unix Concepts and Applications een aanrader.

Dat was een basisintroductie tot argument parsing. Bijna alle programmeertalen ondersteunen argument parsing. Python vormt daarop geen uitzondering. Er zijn drie veelgebruikte manieren om argumenten in Python te parsen:

  • sys.argv
  • getopt
  • argparse

We nemen deze opties nu één voor één door en bekijken hoe je ze gebruikt om argumenten (en opties) te parsen. Laten we chronologisch te werk gaan.

Argument parsing met sys.argv

Laten we simpel beginnen. In dit eerste voorbeeld maak je een Python-bestand demo1.py. Je programma accepteert een willekeurig aantal argumenten die bij het uitvoeren via de command line (of terminal) worden doorgegeven. Het programma print de doorgegeven argumenten en het totale aantal argumenten.

Als je bijvoorbeeld python demo1.py abc 123 uitvoert, levert het programma dit op:

Number of arguments: 3
Argument(s) passed: ['demo1.py', 'abc', '123']

Merk op dat het eerste argument altijd de naam van het Python-bestand is. Je kunt de code aanpassen om dat uit te sluiten.

Dan nu de code:

import sys

print('Number of arguments: {}'.format(len(sys.argv)))
print('Argument(s) passed: {}'.format(str(sys.argv)))

Je importeert eerst de Python-module sys, die standaard met Python wordt meegeleverd. Vervolgens gebruik je de submodule argv, die de lijst retourneert met argumenten die aan een Python-script zijn doorgegeven, waarbij argv[0] de naam van het script bevat. Als je sys.argv in een codecel als volgt uitvoert, krijg je de lijst met configuratiebestanden die ervoor zorgen dat de IPython-kernel goed werkt. Het is beter om daar niet aan te zitten.

sys.argv
['/home/nbuser/anaconda3_501/lib/python3.6/site-packages/ipykernel/__main__.py',
 '-f',
 '/home/nbuser/.local/share/jupyter/runtime/kernel-dabba4f7-e3e0-4c39-99d2-261ba835c53f.json']

Nu bekijken we hoe je de module getopt gebruikt om argumenten (en opties) te parsen.

Argument parsing met getopt

Vergeleken met sys.argv biedt de module getopt veel meer flexibiliteit. Ontwerpen we eerst een voorbeeldsituatie en schrijven we daar de code bij.

Stel, je hebt een Python-script uitgebracht dat je nog niet hebt gedocumenteerd. Maar je wilt gebruikers wel zinvolle feedback geven als ze het script op een onbedoelde manier uitvoeren. Je Python-script doet iets simpels: twee getallen optellen en het resultaat geven. De enige voorwaarde is dat de gebruiker de inputs via command-line-argumenten samen met het Python-script meegeeft.

Iets praktischer: idealiter voer je het script zo uit:

python add_numbers.py -a 3 -b 8

De output moet 11 zijn. Hier zijn -a en -b de opties, en 3 en 8 de argumenten die je aan het script meegeeft. De opties verhogen niet alleen de leesbaarheid, maar helpen ook de verwerkingslogica te bepalen (stel dat je zou delen in plaats van optellen). Laten we naar de code kijken.

import getopt
import sys

# Get the arguments from the command-line except the filename
argv = sys.argv[1:]
sum = 0

try:
    # Define the getopt parameters
    opts, args = getopt.getopt(argv, 'a:b:', ['foperand', 'soperand'])
    # Check if the options' length is 2 (can be enhanced)
    if len(opts) == 0 and len(opts) > 2:
      print ('usage: add.py -a <first_operand> -b <second_operand>')
    else:
      # Iterate the options and get the corresponding values
      for opt, arg in opts:
         sum += int(arg)
      print('Sum is {}'.format(sum))

except getopt.GetoptError:
    # Print something useful
    print ('usage: add.py -a <first_operand> -b <second_operand>')
    sys.exit(2)

Het idee is om eerst alle argumenten op te halen met sys.argv en ze dan te verwerken. Dan nu de belangrijkste regel code: opts, args = getopt.getopt(argv, 'a:b:', ['foperand', 'soperand'])

De signatuur van de methode getopt() ziet er zo uit:

getopt.getopt(args, shortopts, longopts=[])

  • args is de lijst met argumenten die vanaf de command line zijn doorgegeven.
  • shortopts is waar je de optielabels opgeeft. Als je a: opgeeft, betekent dit dat je script de optie a moet krijgen, gevolgd door een waarde als argument. Technisch kun je hier een willekeurig aantal opties gebruiken. Als je deze opties vanaf de command line doorgeeft, moeten ze voorafgegaan worden door '-'.
  • longopts is waar je de uitgebreide versies van de shortopts kunt specificeren. Die moeten voorafgegaan worden door '--'.

Je definieerde de shortopts als a:b:, wat betekent dat je Python-script twee opties als letters accepteert: 'a' en 'b'. Door ':' te specificeren, geef je expliciet aan dat deze opties gevolgd worden door argumenten.

Je definieerde de longopts als ['foperand', 'soperand'], wat inhoudt dat de code f_operand en s_operand kan accepteren in plaats van a en b als opties. Deze moeten echter altijd met -- voorafgegaan worden.

De module getopt biedt ook een handige exceptieklasse GetoptError om nuttige meldingen te definiëren en zo de gebruiker te begeleiden bij het juiste gebruik van je Python-script. Daarom heb je het functionele deel in een try-blok geplaatst en het except-blok overeenkomstig gedefinieerd.

Zo kun je het Python-script uitvoeren:

python script

Let op dat het bovenstaande script niet is ingericht om de longopts af te handelen. Dat kun je zelf als oefening proberen.

Nu bekijken we hoe je argparse gebruikt voor argument parsing.

Argument parsing met argparse

Uit de twee bovenstaande opties blijkt al dat ze niet erg leesbaar zijn. Als je argparse in actie ziet, zul je het ermee eens zijn dat die twee ook minder flexibel zijn. Om het gebruik van argparse te begrijpen, beginnen we met een codefragment dat het scenario uit de vorige sectie implementeert.

import argparse

# Construct the argument parser
ap = argparse.ArgumentParser()

# Add the arguments to the parser
ap.add_argument("-a", "--foperand", required=True,
   help="first operand")
ap.add_argument("-b", "--soperand", required=True,
   help="second operand")
args = vars(ap.parse_args())

# Calculate the sum
print("Sum is {}".format(int(args['foperand']) + int(args['soperand'])))

Allereerst: argparse wordt, net als de andere twee modules hierboven, standaard met Python geïnstalleerd. Je begint met het instantiëren van het argparse-object. De rest wordt dan een stuk eenvoudiger om te schrijven. Neem bijvoorbeeld de volgende regel code:

ap.add_argument("-a", "--foperand", required=True, help="first operand")

Hier voeg je het argument toe dat je verwacht meegegeven te krijgen wanneer het Python-script wordt uitgevoerd. Je geeft de lettervariant van het argument op, samen met de uitgebreide vorm. Door required=True te gebruiken, vraag je de gebruiker expliciet om dat specifieke argument te leveren. Tot slot voeg je een begrijpelijke beschrijving van het argument toe, die aan de gebruiker wordt getoond als hij het script niet op de juiste manier uitvoert.

De definitie van het tweede argument is hetzelfde. Je benadert de opgegeven argumenten door hun respectieve indices te gebruiken.

Het bovenstaande codefragment laat duidelijk zien hoe eenvoudig en flexibel het is om command-line-argumenten te definiëren met argparse. Zo kun je met het bovenstaande Python-script aan de slag:

python script

Zie je hoe veel eenvoudiger het met argparse wordt?

Wat nu?

Bedankt dat je deze tutorial tot het einde hebt gelezen. Je kent nu de native Python-modules die argumenten kunnen parsen die vanaf de command line samen met je Python-script worden doorgegeven. Als oefening kun je je machine learning- en data science-projecten hierop aanpassen om argument parsing te faciliteren en ze om te vormen tot handige scripttools. Niet alleen voor machine learning of data science, maar overal waar je het relevant vindt. Dat was het voor vandaag. Als je je Python-vaardigheden verder wilt verbeteren, kijk dan eens naar DataCamp’s cursus Python Data Science Toolbox (Part 1).

Onderwerpen

Gerelateerd