Argomenti della riga di comando in Python

Panoramica

Essendo Python un linguaggio di programmazione molto popolare, oltre ad avere il supporto per la maggior parte dei sistemi operativi e molte librerie che semplificano l'elaborazione degli argomenti della riga di comando, è diventato ampiamente utilizzato per creare strumenti da riga di comando per molti scopi. Questi strumenti possono variare da semplici app CLI a quelle più complesse, come quelle di AWS awscli strumento.

Strumenti complessi come questo sono generalmente controllati dall'utente tramite argomenti della riga di comando, che consente all'utente di utilizzare comandi specifici, impostare opzioni e altro. Ad esempio, queste opzioni potrebbero indicare allo strumento di generare informazioni aggiuntive, leggere dati da una fonte specifica o inviare output a una determinata posizione.

In generale, gli argomenti vengono passati agli strumenti CLI in modo diverso, a seconda del sistema operativo:

  • Tipo Unix: - seguito da una lettera, come -h, o -- seguito da una parola, come --help
  • Windows: / seguito da una lettera o da una parola, come /help

Questi diversi approcci esistono per ragioni storiche. Molti programmi su sistemi simili a Unix supportano sia la notazione a trattino singolo che quella a trattino doppio. La notazione del trattino singolo viene utilizzata principalmente con le opzioni a lettera singola, mentre i trattini doppi presentano un elenco di opzioni più leggibile, che è particolarmente utile per opzioni complesse che devono essere più esplicite.

Note:: In questo articolo ci concentreremo esclusivamente sul formato simile a Unix di - ed --.

Tieni presente che sia il nome che il significato di un argomento sono specifici di un programma: non esiste una definizione generale, a parte alcune convenzioni comuni come --help per ulteriori informazioni sull'utilizzo dello strumento. Come sviluppatore di uno script Python, deciderai quali argomenti fornire al chiamante e cosa fanno. Ciò richiede una valutazione adeguata.

Man mano che l'elenco degli argomenti disponibili cresce, il codice diventerà più complesso nel tentativo di analizzarli accuratamente. Fortunatamente, in Python sono disponibili numerose librerie che possono aiutarti in questo. Tratteremo alcune delle soluzioni più comuni, che vanno dal “fai da te” con sys.argv, all'approccio “fatto per te” con argparse.

Gestire gli argomenti della riga di comando con Python

Python 3+ e l'ecosistema circostante supportano diversi modi di gestire gli argomenti della riga di comando. Ci sono molti librerie che affascinano l'analisi degli argomenti della riga di comando.

Il modo integrato è utilizzare il file sys modulo. In termini di nomi e di utilizzo, si riferisce direttamente alla libreria C (libc).

Il secondo modo è il getopt modulo, che gestisce sia opzioni brevi che lunghe, inclusa la valutazione dei valori dei parametri.

Il modulo argparse, che deriva da optparse modulo (disponibile fino a Python 2.7).

Il docopt modulo, che è disponibili su GitHub, consente anche la stessa funzionalità.

Recentemente, la absl anche la biblioteca sta guadagnando terreno, come mezzo per sostituire optparse ed getopt().

Ognuno di questi modi ha i suoi pro e contro, quindi vale la pena valutarli per vedere quale si adatta meglio alle tue esigenze.

Il modulo di sistema

Questo è un modulo base fornito con Python fin dai primi giorni. Adotta un approccio molto simile all'utilizzo della libreria C argc/argv per accedere agli argomenti. IL modulo sys implementa gli argomenti della riga di comando in una semplice struttura di elenco denominata sys.argv.

Ogni elemento della lista rappresenta un singolo argomento. Il primo elemento dell'elenco, sys.argv[0], è il nome dello script Python. Il resto degli elementi dell'elenco, sys.argv[1] a sys.argv[n], sono gli argomenti della riga di comando da 2 a n.

Come delimitatore tra gli argomenti viene utilizzato uno spazio. I valori degli argomenti che contengono uno spazio devono essere racchiusi tra virgolette per poter essere analizzati correttamente sys.

L'equivalente di argc è solo il numero di elementi nell'elenco. Per ottenere questo valore, utilizzare Python len() operatore. Lo mostreremo in un esempio di codice più avanti.

Stampa del primo argomento CLI

In questo primo esempio, il nostro script determinerà il modo in cui è stato chiamato. Questa informazione è conservata nel primo argomento della riga di comando, indicizzato con 0. Il codice seguente mostra come ottenere il nome del tuo script Python:

import sys

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

Salva questo codice in un file denominato arguments-program-name.py, quindi chiamarlo come mostrato di seguito. L'output è il seguente e contiene il nome del file, incluso il percorso completo:

$ 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

Come puoi vedere dalla seconda chiamata sopra, non solo otteniamo il nome del file Python, ma anche il percorso completo utilizzato per chiamarlo.

Conteggio del numero di argomenti

In questo secondo esempio contiamo semplicemente il numero di argomenti della riga di comando utilizzando il built-in len() metodo. sys.argv è l'elenco che dobbiamo esaminare. Nel codice seguente, otteniamo il numero di argomenti e poi sottraiamo 1 perché uno di questi argomenti (cioè il primo) è sempre impostato come nome del file, il che non sempre ci è utile. Pertanto, il numero effettivo di argomenti passati dall'utente è len(sys.argv) - 1:

import sys


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

Salva e chiama questo file argomenti-count.py. Alcuni esempi di chiamata di questo script sono mostrati di seguito. Ciò include tre diversi scenari:

  • Una chiamata senza ulteriori argomenti della riga di comando
  • Una chiamata con due argomenti
  • Una chiamata con due argomenti, dove il secondo è una stringa tra virgolette contenente uno spazio
$ 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
Iterazione degli argomenti

Il nostro terzo esempio restituisce ogni singolo argomento inviato allo script Python, tranne il nome del programma stesso. Pertanto, eseguiamo il ciclo degli argomenti della riga di comando iniziando con il secondo elemento dell'elenco. Ricordiamo che questo è l'indice 1 poiché le liste sono basate su 0 in Python:

import sys


arguments = len(sys.argv) - 1


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

Di seguito chiamiamo il nostro codice, che è stato salvato nel file topics-output.py. Come fatto con il nostro esempio precedente, l'output illustra tre diverse chiamate:

  • Una chiamata senza argomenti
  • Una chiamata con due argomenti
  • Una chiamata con due argomenti, dove il secondo argomento è una stringa tra virgolette contenente uno spazio
$ 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

Ricorda, lo scopo di mostrare l'esempio della stringa tra virgolette è che i parametri sono solitamente delimitati da uno spazio, salvo che sono circondati da virgolette.

Bandiere di discesa in corda doppia (absl)

La libreria Flags di Abseil ha lo scopo di portare in produzione gli argomenti della riga di comando, con argomenti della riga di comando distribuiti. Quando un modulo utilizza i flag della riga di comando e viene importato in un altro modulo, l'altro modulo importa anche le bandieree può elaborarli inoltrandoli al modulo importato.

Ciò rende gli argomenti complessi della riga di comando condivisi tra i moduli più semplici e meno dettagliati.

Inoltre, la libreria consente di definire i valori predefiniti, le descrizioni e il tipo di dati degli argomenti, quindi non sono necessari ulteriori controlli e conversioni.

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}!")

I tipi di dati supportati sono:

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

Oltre DEFINE_multi_integer(), DEFINE_multi_string() ed DEFINE_multi_enum() per input con più argomenti. Inoltre, correre --help, --helpfull, ecc. stampa i flag esistenti e le loro descrizioni, in diversi formati.

Dai un'occhiata alla nostra guida pratica e pratica per l'apprendimento di Git, con le migliori pratiche, gli standard accettati dal settore e il cheat sheet incluso. Smetti di cercare su Google i comandi Git e in realtà imparare esso!

La libreria consente inoltre di definire le convalide, sia in termini di intervallo, come valori basati su numeri interi aventi un upper_bound or lower_bound è accettabile e si eseguono metodi arbitrari per verificare i valori:

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

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

Raccogliendoli in un esempio concreto:

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

Il modulo argparse

Il modulo argparse è disponibile a partire da Python 3.2 e un miglioramento di optparse modulo che esiste fino a Python 2.7. La documentazione di Python contiene una descrizione dell'API e un tutorial che copre tutti i metodi in dettaglio.

Il modulo offre un'interfaccia a riga di comando con un output standardizzato, mentre le prime due soluzioni lasciano gran parte del lavoro nelle tue mani. argparse consente la verifica di argomenti fissi e facoltativi, con controllo del nome sia in stile breve che lungo. Come argomento facoltativo predefinito, include -h, insieme alla sua versione lunga --help. Questo argomento è accompagnato da un messaggio di aiuto predefinito che descrive gli argomenti accettati.

Il codice seguente mostra l'inizializzazione del parser e l'output seguente che mostra la chiamata di base, seguita dal messaggio di aiuto. A differenza delle chiamate Python che abbiamo utilizzato negli esempi precedenti, ricorda di utilizzare Python 3 con questi esempi:


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

Nel passaggio successivo, aggiungeremo una descrizione personalizzata al messaggio di aiuto per i nostri utenti. L'inizializzazione del parser in questo modo consente un testo aggiuntivo. Il codice seguente memorizza la descrizione nel file text variabile, che è data esplicitamente a argparse classe come il description parametro. Chiamando questo codice qui sotto, puoi vedere come appare l'output:


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

Come passaggio finale aggiungeremo un argomento opzionale denominato -V, che ha un argomento di stile lungo corrispondente denominato --version. Per farlo utilizziamo il metodo add_argument() che chiamiamo con tre parametri (visualizzati per --version, soltanto):

  • Il nome del parametro: --version
  • Il testo di aiuto per il parametro: help="show program version"
  • Azione (senza valore aggiuntivo): action="store_true"

Il codice sorgente per questo è visualizzato di seguito. Leggere gli argomenti nella variabile chiamata args viene effettuato tramite il parse_args() metodo dal parser oggetto. Tieni presente che invii sia la versione breve che quella lunga in un'unica chiamata. Infine, controlli se gli attributi args.V or args.version vengono impostati e viene visualizzato il messaggio di versione:


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

Il --version l'argomento non richiede l'immissione di un valore sulla riga di comando. Ecco perché abbiamo impostato l'argomento dell'azione su "store_true". In altri casi potresti aver bisogno di un valore assegnato aggiuntivo, ad esempio se specifichi un determinato volume, altezza o larghezza. Questo è mostrato nel prossimo esempio. Per impostazione predefinita, tieni presente che tutti gli argomenti vengono interpretati come stringhe:


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)

Qui mostriamo cosa succede quando si inviano valori di argomento diversi. Ciò include sia la versione breve che quella lunga, nonché il messaggio di aiuto:

$ 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

Il modulo getopt

Come avrai notato prima, il sys Il modulo divide la stringa della riga di comando solo in singole sfaccettature. Il Pitone modulo getopt va un po' oltre ed estende la separazione della stringa di input mediante la convalida dei parametri. Basato sul getopt Funzione C, consente opzioni sia brevi che lunghe, inclusa l'assegnazione di un valore.

In pratica, richiede il sys modulo per elaborare correttamente i dati di input. Per fare ciò, entrambi i sys modulo e il getopt il modulo deve essere caricato in anticipo. Successivamente, dall'elenco dei parametri di input rimuoviamo il primo elemento dell'elenco (vedere il codice seguente) e memorizziamo l'elenco rimanente di argomenti della riga di comando nella variabile chiamata argument_list:


import getopt, sys


full_cmd_arguments = sys.argv


argument_list = full_cmd_arguments[1:]

print argument_list

Le argomentazioni in argument_list ora può essere analizzato utilizzando il file getopts() metodo. Ma prima di farlo, dobbiamo raccontarlo getopts() su quali parametri sono validi. Sono definiti così:

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

Ciò significa che questi argomenti sono quelli che consideriamo validi, insieme ad alcune informazioni extra:

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

Potresti aver notato che o l'opzione breve era preceduta da due punti, :. Questo dice getopt che a questa opzione dovrebbe essere assegnato un valore.

Questo ora ci consente di elaborare un elenco di argomenti. IL getopt() Il metodo richiede la configurazione di tre parametri: l'elenco degli argomenti effettivi da argv, così come le opzioni brevi e lunghe valide (mostrate nel frammento di codice precedente).

La chiamata al metodo stessa viene mantenuta in un'istruzione try-catch per coprire gli errori durante la valutazione. Viene sollevata un'eccezione se viene scoperto un argomento che non fa parte dell'elenco come definito in precedenza. Lo script Python stamperà il messaggio di errore sullo schermo e uscirà con il codice di errore 2:

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

Infine, gli argomenti con i valori corrispondenti vengono memorizzati nelle due variabili denominate arguments ed values. Ora puoi valutare facilmente queste variabili nel tuo codice. Possiamo usare a for-loop per scorrere l'elenco degli argomenti riconosciuti, una voce dopo la successiva.


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

Di seguito puoi vedere l'output dell'esecuzione di questo codice. Mostreremo come il programma reagisce sia agli argomenti validi che a quelli non validi:

$ 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

L'ultima chiamata al nostro programma all'inizio può sembrare un po' confusa. Per capirlo, devi sapere che le opzioni abbreviate (a volte chiamate anche flag) possono essere usate insieme ad un singolo trattino. Ciò consente al tuo strumento di accettare più facilmente molte opzioni. Ad esempio, chiamare python arguments-getopt.py -vh è come chiamare python arguments-getopt.py -v -h. Quindi nell'ultima chiamata sopra, il getopt il modulo pensava che l'utente stesse tentando di passare -e come opzione, che non è valida.

Conclusione

In questo articolo abbiamo mostrato molti metodi diversi per recuperare gli argomenti della riga di comando in Python, incluso l'utilizzo sys, getopte argparse. Questi moduli variano in termini di funzionalità, alcuni forniscono molto più di altri. sys è completamente flessibile, mentre entrambi getopted argparse richiedono una certa struttura. Al contrario, coprono la maggior parte del lavoro complesso che sys lascia a te. Dopo aver esaminato gli esempi forniti, dovresti essere in grado di determinare quale modulo si adatta meglio al tuo progetto.

In questo articolo non abbiamo parlato di altre soluzioni come la docopts modulo, ne abbiamo appena parlato. Questo modulo segue un approccio totalmente diverso e verrà spiegato in dettaglio in uno dei prossimi articoli.

Riferimenti

Timestamp:

Di più da Impilamento