Scopo | Analizza le opzioni e gli argomenti di riga di comando |
Versione Python | 2.7 e superiore |
A partire dal 1 gennaio 2021 le versioni 2.x di Python non sono piu' supportate. Ti invito a consultare la corrispondente versione 3.x dell'articolo per il modulo argparse
Il modulo argparse è stato aggiunto a Python 2.7 come rimpiazzo per optparse . L'implementazione di argparse supporta caratteristiche che non sarebbe stato facile aggiungere ad optparse , e che avrebbe richiesto modifiche all'API incongruenti con le versioni precedenti; così è stato portato nella libreria un nuovo modulo. optparse è ancora supportato, ma difficilmente riceverà nuove caratteristiche.
L'API per argparse è simile a quella fornita da optparse , ed in molti casi potrà essere usato direttamente come rimpiazzo aggiornando i nomi delle classi ed i metodi usati. Ci sono pochi punti nei quali non è stato possibile preservare la compatibilità diretta visto che, comunque, sono state aggiunte nuove funzionalità.
Occorrerà decidere se aggiornare i programmi esistenti caso per caso. Se si è scritto del codice supplementare per superare le limitazioni di optparse , si potrebbe aggiornare per ridurre la quantità di codice che occorre manutenere. I nuovi programmi probabilmente dovrebbero usare argparse , se è disponibile su tutte le piattaforme di sviluppo.
Quando si usa argparse , il primo passo consiste nel creare l'oggetto parser, quindi dirgli quali argomenti deve attendersi. Il parser può poi essere usato per elaborare gli argomenti di riga di comando quando il programma viene eseguito.
La classe parser è
ArgumentParser
. Il costruttore richiede diversi argomenti per impostare le descrizioni usate nel testo di aiuto per il programma e per altri comportamenti ed impostazioni globali.
import argparse
parser = argparse.ArgumentParser(description='Questo è un programma di esempio di PyMOTW')
argparse
è una libreria completa per l'elaborazione degli argomenti. Essi possono attivare diverse azioni, specificate dall'argomento
action
di
add_argument()
. Le azioni supportate comprendono la memorizzazione dell'argomento (singolarmente o come parte di una lista), la memorizzazione di un valore costante quando viene rilevato l'argomento (compresa la gestione speciale per i valori true/false degli switch booleani), il conteggio del numero di volte nelle quali viene rilevato un argomento e la chiamata di un callback.
L'azione predefinita è la memorizzazione del valore del argomento. In questo caso, se viene passato un tipo, il valore viene convertito in quel tipo prima di essere memorizzato. Se viene passato l'argomento dest il valore viene salvato ad un attributo di quel nome nell'oggetto Namespace restituito quando la riga di comando viene analizzata.
Una volta che tutti gli argomenti sono definiti, si può analizzare la riga di comando passando una sequenza di stringhe di argomento a
parse_args()
. Nella modalità predefinita, gli argomenti sono recuperati da
sys.argv[1:]
, ma si può passare anche una propria lista. Le opzioni sono elaborate usando la sintassi GNU/POSIX, in modo che opzioni e valori di argomenti possano essere mescolati nella sequenza.
Il valore restituito da
parse_args()
è un
Namespace
che contiene gli argomenti del comando. L'oggetto contiene i valori degli argomenti come attributi, in modo che se l' argomento
dest
è
"miaopzione"
, al suo valore si potrà accedere come
args.miaopzione
Ecco un semplice esempio con tre diverse opzioni: una booleana (
-a
), una stringa (
-b
) ed un intero (
-c
)
import argparse
parser = argparse.ArgumentParser(description='Breve applicazione di esempio')
parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)
print parser.parse_args(['-a', '-bval', '-c', '3'])
Ci sono modi diversi per passare valori alle opzioni a carattere singolo: l'esempio di cui sopra usa due forme diverse;
-bvalore
e
-c valore
$ python argparse_short.py Namespace(a=True, b='val', c=3)
Il tipo del valore associato a
'c'
.nell'output è un intero, visto che ad
ArgumentParser
è stato detto di convertire l'argomento prima di memorizzarlo.
I nomi di opzione "lunghi", con più di un carattere nel proprio nome, sono gestiti allo stesso modo
import argparse
parser = argparse.ArgumentParser(description='Esempio con nomi di opzione lunghi')
parser.add_argument('--noarg', action="store_true", default=False)
parser.add_argument('--witharg', action="store", dest="witharg")
parser.add_argument('--witharg2', action="store", dest="witharg2", type=int)
print parser.parse_args([ '--noarg', '--witharg', 'val', '--witharg2=3' ])
Ed i risultati sono simili:
$ python argparse_long.py Namespace(noarg=True, witharg='val', witharg2=3)
Un'area nella quale argparse differisce da optparse è il trattamento dei valori degli argomenti non opzionali. Mentre optparse rimane ancorato all'analisi dell'opzione, argparse è uno strumento completo per l'analisi degli argomenti di riga di comando, e gestisce bene anche gli argomenti non opzionali.
import argparse
parser = argparse.ArgumentParser(description='Esempio con argomenti non associati ad opzione')
parser.add_argument('count', action="store", type=int)
parser.add_argument('units', action="store")
print parser.parse_args()
In questo esempio, l'argomento count è un intero, e l'argomento units viene salvato come stringa. Se entrambi non vengono passati nella riga di comando, oppure il valore fornito non può essere convertito nel tipo corretto, viene riportato un errore.
$ python argparse_arguments.py 3 inches amespace(count=3, units='inches') $ python argparse_arguments.py some inches usage: argparse_arguments.py [-h] count units argparse_arguments.py: error: argument count: invalid int value: 'some' $ python argparse_arguments.py usage: argparse_arguments.py [-h] count units argparse_arguments.py: error: too few arguments
Ci sono sei azioni built-in che possono essere attivate quando viene rilevato un argomento:
store
store_const
store_true
/
store_false
append
append_const
version
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-s', action='store', dest='valore_semplice',
help='Conserva un semplice valore')
parser.add_argument('-c', action='store_const', dest='valore_costante',
const='value-to-store',
help='Conserva un valore costante')
parser.add_argument('-t', action='store_true', default=False,
dest='switch_booleano',
help='Imposta uno switch a true')
parser.add_argument('-f', action='store_false', default=False,
dest='switch_booleano',
help='Imposta uno switch a false')
parser.add_argument('-a', action='append', dest='collezione',
default=[],
help='Aggiunge valori ripetuti ad una lista',
)
parser.add_argument('-A', action='append_const', dest='collezione_costanti',
const='valore-1-da-aggiungere',
default=[],
help='Aggiunge valori diversi ad una lista')
parser.add_argument('-B', action='append_const', dest='collezione_costanti',
const='valore-2-da-aggiungere',
help='Aggiunge valori diversi ad una lista')
parser.add_argument('--version', action='version', version='%(prog)s 1.0')
results = parser.parse_args()
print 'valore_semplice =', results.valore_semplice
print 'valore_costante =', results.valore_costante
print 'switch_booleano =', results.switch_booleano
print 'collezione =', results.collezione
print 'collezione_costanti =', results.collezione_costanti
$ python argparse_action.py -h usage: argparse_action.py [-h] [-s valore_semplice] [-c] [-t] [-f] [-a COLLEZIONE] [-A] [-B] [--version] optional arguments: -h, --help show this help message and exit -s valore_semplice Conserva un semplice valore -c Conserva un valore costante -t Imposta uno switch a true -f Imposta uno switch a false -a COLLEZIONE Aggiunge valori ripetuti ad una lista -A Aggiunge valori diversi ad una lista -B Aggiunge valori diversi ad una lista --version show program's version number and exit $ python argparse_action.py -s value valore_semplice = value valore_costante = None switch_booleano = False collezione = [] collezione_costanti = [] $ python argparse_action.py -c valore_semplice = None valore_costante = value-to-store switch_booleano = False collezione = [] collezione_costanti = [] $ python argparse_action.py -t valore_semplice = None valore_costante = None switch_booleano = True collezione = [] collezione_costanti = [] $ python argparse_action.py -f valore_semplice = None valore_costante = None switch_booleano = False collezione = [] collezione_costanti = [] $ python argparse_action.py -a uno -a due -a tre valore_semplice = None valore_costante = None switch_booleano = False collezione = ['uno', 'due', 'tre'] collezione_costanti = [] $ python argparse_action.py -B -A valore_semplice = None valore_costante = None switch_booleano = False collezione = [] collezione_costanti = ['value-2-da-aggiungere', 'valore-1-da-aggiungere'] $ python argparse_action.py --version argparse_action.py 1.0
La sintassi predefinita per le opzioni è basata sulla convenzione Unix di contraddistinguere gli switch da riga di comando usando il prefisso "-". argparse supporta altri prefissi, quindi si può rendere il proprio programma conforme ai valori predefiniti della piattaforma locale (es.: usare "/" in Windows) oppure seguire una diversa convenzione.
import argparse
parser = argparse.ArgumentParser(description='Modifica i caratteri prefisso opzione',
prefix_chars='-+/',
)
parser.add_argument('-a', action="store_false", default=None,
help='Disattiva A',
)
parser.add_argument('+a', action="store_true", default=None,
help='Attiva A',
)
parser.add_argument('//noarg', '++noarg', action="store_true", default=False)
print parser.parse_args()
Impostare il parametro
prefix_chars
per
ArgumentParser
ad una stringa che contiene tutti i caratteri ammessi che dovrebbero identificare una opzione. E' importante comprendere che, sebbene
prefix_chars
determini i caratteri concessi per gli switch, la definizione dei singoli argomenti specifica la sintassi per un certo switch. Questo fornisce un controllo esplicito sul fatto che le opzioni chu usano prefissi diversi siano alias (come potrebbe essere il caso per la sintassi di una riga di comando indipendente dalla piattaforma) od alternative (es. usare "+" per indicare l'attivazione di uno switch e "-" per la disattivazione). Nell'esempio qui sopra,
+a
e
-1
sono argomenti distinti, e
++noarg
ma non
--noarg
.
$ python argparse_prefix_chars.py -h usage: argparse_prefix_chars.py [-h] [-a] [+a] [//noarg] Modifica i caratteri prefisso opzione optional arguments: -h, --help show this help message and exit -a Disattiva A +a Attiva A //noarg, ++noarg $ python argparse_prefix_chars.py +a Namespace(a=True, noarg=False) $ python argparse_prefix_chars.py -a Namespace(a=False, noarg=False) $ python argparse_prefix_chars.py //noarg Namespace(a=None, noarg=True) $ python argparse_prefix_chars.py ++noarg Namespace(a=None, noarg=True) $ python argparse_prefix_chars.py --noarg usage: argparse_prefix_chars.py [-h] [-a] [+a] [//noarg] argparse_prefix_chars.py: error: unrecognized arguments: --noarg
Negli esempi fino a qui, l'elenco degli argomenti forniti al parser provenivano da un elenco passato esplicitamente, oppure erano recuperati in modo implicito da
sys.argv
. Passare esplicitamente un elenco è utile quando si usa
argparse
per elaborare istruzioni tipo riga di comando che non provengono dalla riga di comando stessa (tipo da un file di configurazione).
import argparse
from ConfigParser import ConfigParser
import shlex
parser = argparse.ArgumentParser(description='Breve applicazione di esempio')
parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)
config = ConfigParser()
config.read('argparse_witH_shlex.ini')
config_value = config.get('cli', 'options')
print 'Config :', config_value
argument_list = shlex.split(config_value)
print 'Elenco param.:', argument_list
print 'Risultati :', parser.parse_args(argument_list)
shlex facilita la divisione della stringa memorizzata nel file di configurazione
$ python argparse_with_shlex.py Config : -a -b 2 Elenco param.: ['-a', '-b', '2'] Risultati : Namespace(a=True, b='2', c=None)
Un'alternativa all'elaborare personalmente il file di configurazione è di dire ad argparse come riconoscere un argomento che fa riferimento ad un file di input che contiene un insieme di argomenti da elaborare tramite fromfile_prefix_chars .
import argparse
from ConfigParser import ConfigParser
import shlex
parser = argparse.ArgumentParser(description='Breve applicazione di esempio',
fromfile_prefix_chars='@',
)
parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)
print parser.parse_args(['@argparse_fromfile_prefix_chars.txt'])
Questo esempio si interrompe quando trova un argomento prefissato da
@
, quindi legge il file il cui nome ha ricevuto come argomento per trovare ulteriori argomenti. Ad esempio se il file di input
argparse_fromfile_prefix_chars.txt
contiene una serie di argomenti, uno per riga:
-a -b 2
L'output prodotto quando viene elaborato il file è:
$ python argparse_fromfile_prefix_chars.py Namespace(a=True, b='2', c=None)
argparse aggiungerà automaticamente le opzioni per generare l'aiuto e mostrare le informazioni circa la versione della propria applicazione, se viene opportunamente configurato.
L' argomento di ArgumentParser add_help controlla le opzioni relative all'aiuto.
import argparse
parser = argparse.ArgumentParser(add_help=True)
parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)
print parser.parse_args()
Le opzioni di aiuto (
-h
ed
--help
) sono aggiunte in modalità predefinita; possono essere disabilitate impostando
add_help
a
false
.
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)
print parser.parse_args()
Sebbene
-h
ed
--help
siano uno standard defacto per i nomi di opzioni per richiedere aiuto; alcune applicazioni od usi di
argparse
potrebbero non avere necessità di fornire un aiuto oppure potrebbero usare questi nomi di opzione per altri scopi.
$ python argparse_with_help.py -h usage: argparse_with_help.py [-h] [-a] [-b B] [-c C] optional arguments: -h, --help show this help message and exit -a -b B -c C $ python argparse_without_help.py -h usage: argparse_without_help.py [-a] [-b B] [-c C] argparse_without_help.py: error: unrecognized arguments: -h
Le opzioni di versione (
-v
e
--version
) sono aggiunte quando
version
viene impostato nel costruttore di
ArgumentParser
.
import argparse
parser = argparse.ArgumentParser(version='1.0')
parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)
print parser.parse_args()
print 'Questo non viene stampato!'
Entrambi i formati dell'opzione stampano la stringa della versione del programma; poi causano l'uscita immediata dal programma stesso.
$ python argparse_with_version.py -h usage: argparse_with_version.py [-h] [-v] [-a] [-b B] [-c C] optional arguments: -h, --help show this help message and exit -v, --version show program's version number and exit -a -b B -c C $ python argparse_with_version.py -v 1.0 $ python argparse_with_version.py --version 1.0
argparse comprende diverse caratteristiche per l'organizzazione dei propri parser di argomenti, per facilitarne l'implementazione o per migliorare l'usabilità dell'output di aiuto.
E' comune la necessità di implementare un gruppo di programmi da riga di comando che ricevono tutti un insieme di argomenti, per poi specializzarsi in un qualche modo. Ad esempio, se i tutti i programmi necessitano di una autenticazione dell'utente prima di intraprendere una azione effettiva, potrebbero avere tutti bisogno di supportare le opzioni
--user
e
--password
. Piuttosto che aggiungere esplicitamente le opzioni ad ogni
ArgumentParser
, si può definire un parser "genitore" con le opzioni condivise, poi fare da esso ereditare ai parser dei singoli programmi le sue opzioni.
Il primo passo è impostare il parser con le definizioni degli argomenti comuni. Visto che ogni utilizzatore del parser genitore vorrà aggiungere le stesse opzioni di aiuto, causando una eccezione, occorre disabilitare la generazione di aiuto automatico nel parser di base.
import argparse
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--user', action="store")
parser.add_argument('--password', action="store")
Quindi si crea un altro parser con impostato parents ;
import argparse
import argparse_parent_base
parser = argparse.ArgumentParser(parents=[argparse_parent_base.parser])
parser.add_argument('--local-arg', action="store_true", default=False)
print parser.parse_args()
Ed il programma risultante otterrà tutte e tre le opzioni:
$ python argparse_uses_parent.py -h usage: argparse_uses_parent.py [-h] [--user USER] [--password PASSWORD] [--local-arg] optional arguments: -h, --help show this help message and exit --user USER --password PASSWORD --local-arg
L'esempio precedente evidenziava che l'aggiunta di due gestori di argomenti ad un parser usando lo stesso nome di argomento causa una eccezione. Per modificare il comportamento per la risoluzione dei conflitti si passa
conflict_handler
. I due gestori built-in sono
error
(il predefinito) e
resolve
, il quale sceglie un gestore in base all'ordine nel quale sono stati aggiunti.
import argparse
parser = argparse.ArgumentParser(conflict_handler='resolve')
parser.add_argument('-a', action="store")
parser.add_argument('-b', action="store", help='Solo corta')
parser.add_argument('--long-b', '-b', action="store", help='Lunga e corta insieme')
print parser.parse_args(['-h'])
Visto che viene usato l'ultimo gestore con uno specifico nome di argomento, in questo esempio l'opzione a carattere singolo
-b
viene mascherata dall'alias per
--long-b
.
$ python argparse_conflict_handler_resolve.py -h usage: argparse_conflict_handler_resolve.py [-h] [-a A] [--long-b LONG_B] optional arguments: -h, --help show this help message and exit -a A --long-b LONG_B, -b LONG_B Lunga e corta assieme
L'inversione dell'ordine delle chiamate a
add_argument()
, "smaschera" l'opzione a carattere singolo
import argparse parser = argparse.ArgumentParser(conflict_handler='resolve') parser.add_argument('-a', action="store") parser.add_argument('-b', action="store", help='Solo corta') parser.add_argument('--long-b', '-b', action="store", help='Lunga e corta assieme') print parser.parse_args(['-h']) Ora entrambe le opzioni possono essere usate insieme.
$ python argparse_conflict_handler_resolve2.py usage: argparse_conflict_handler_resolve2.py [-h] [-a A] [--long-b LONG_B] [-b B] optional arguments: -h, --help show this help message and exit -a A --long-b LONG_B Long and short together -b B Short alone
argparse raggruppa le definizioni degli argomenti in "gruppi". Nella modalità predefinita, usa due gruppi, uno per le opzioni ed un altro per la richiesta di argomenti basati sula posizione degli stessi.
import argparse
parser = argparse.ArgumentParser(description='Breve semplice applicazione')
parser.add_argument('--optional', action="store_true", default=False)
parser.add_argument('positional', action="store")
print parser.parse_args()
Il raggruppamento viene rispecchiato nelle sezioni separate "positional arguments" (argomenti posizionali) ed "optional arguments" (argomenti opzionali) nell'output di aiuto:
$ python argparse_default_grouping.py -h usage: argparse_default_grouping.py [-h] [--optional] positional Breve semplice applicazione positional arguments: positional optional arguments: -h, --help show this help message and exit --optional
Si può modificare il raggruppamento per renderlo più logico nell'aiuto, in modo che le opzioni od i valori collegati siano documentati assieme. L'esempio di opzioni condivise fatto precedentemente potrebbe essere scritto usando un raggruppamento personalizzato in modo che le opzioni di autenticazione siano mostrate assieme nell'aiuto.
Occorre creare un gruppo "autenticazione" tramite
add_argument_group()
, quindi si aggiunge ognuna delle opzioni legate all'autenticazione al gruppo, invece che al parser di base.
import argparse parser = argparse.ArgumentParser(add_help=False) group = parser.add_argument_group('autenticazione') group.add_argument('--user', action="store") group.add_argument('--password', action="store")
Il programma che usa gli elenchi basati sul gruppo del genitore li elenca nel valore parents , proprio come prima:
import argparse
import argparse_parent_with_group
parser = argparse.ArgumentParser(parents=[argparse_parent_with_group.parser])
parser.add_argument('--local-arg', action="store_true", default=False)
print parser.parse_args()
L'output di aiuto ora mostra le opzioni di autenticazione assieme:
$ python argparse_uses_parent_with_group.py -h usage: argparse_uses_parent_with_group.py [-h] [--user USER] [--password PASSWORD] [--local-arg] optional arguments: -h, --help show this help message and exit --local-arg autenticazione: --user USER --password PASSWORD
Una tipologia speciale della caratteristica di raggruppamento è la definizione di opzioni mutualmente esclusive, che si ottiene usando
add_mutually_exclusive_group()
invece che
add_argument_group()
.
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('-a', action='store_true')
group.add_argument('-b', action='store_true')
print parser.parse_args()
argparse si occupa della forzatura della mutua esclusività, in modo che solo una delle opzioni dal gruppo possa essere fornita.
$ python argparse_mutually_exclusive.py -h usage: argparse_mutually_exclusive.py [-h] [-a | -b] optional arguments: -h, --help show this help message and exit -a -b $ python argparse_mutually_exclusive.py -a Namespace(a=True, b=False) $ python argparse_mutually_exclusive.py -b Namespace(a=False, b=True) $ python argparse_mutually_exclusive.py -a -b usage: argparse_mutually_exclusive.py [-h] [-a | -b] argparse_mutually_exclusive.py: error: argument -b: not allowed with argument -a
L'approccio tramite parser "genitore" descritto qui sopra è un modo per condividere opzioni tra comandi collegati. Un approccio alternativo è quello di combinare i comandi in un programma singolo, utilizzando dei "subparser" per gestire ciascuna porzione della riga di comando. Il risultato viene espresso allo stesso modo di programmi come
svn
,
hg
ed altri con azioni multiple da riga di comando, o sotto comandi.
Un programma che lavori con directory nel file system potrebbe definire dei comandi per creare, eliminare ed elencare il contenuto di una directory in questo modo:
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='comandi')
# Un comando di elenco
list_parser = subparsers.add_parser('elenca', help='Elenco contenuto')
list_parser.add_argument('nomedir', action='store', help='Directory da elencare')
# Un comando di creazione
create_parser = subparsers.add_parser('crea', help='Crea una directory')
create_parser.add_argument('nomedir', action='store', help='Nuova directory da creare')
create_parser.add_argument('--sola-lettura', default=False, action='store_true',
help='Imposta i permessi per evitare di scrivere alla directory',
)
# Un comando di eliminazione
delete_parser = subparsers.add_parser('elimina', help='Elimina una directory')
delete_parser.add_argument('nomedir', action='store', help='La directory da eliminare')
delete_parser.add_argument('--ricorsiva', '-r', default=False, action='store_true',
help='Elimina anche il contenuto della directory',
)
print parser.parse_args()
L'output di aiuto mostra i "subparse" identificati come "comandi" che possono essere specificati nella riga di comando come argomenti posizionali
$ python argparse_subparsers.py -h usage: argparse_subparsers.py [-h] {elenca,crea,elimina} ... positional arguments: {elenca,crea,elimina} comandi elenca Elenco contenuto crea Crea una directory elimina Elimina una directory optional arguments: -h, --help show this help message and exit
Ciascun "subparser" ha anche il proprio aiuto, che descrive gli argomenti e le opzioni per quel comando
$ python argparse_subparsers.py crea -h usage: argparse_subparsers.py crea [-h] [--sola-lettura] nomedir positional arguments: nomedir Nuova directory da creare optional arguments: -h, --help show this help message and exit --sola-lettura Imposta i permessi per evitare di scrivere alla directory
Quando gli argomenti sono elaborati, l'oggetto
Namespace
ritornato da
parse_args()
include solo i valori relativi al comando specificato
$ python argparse_subparsers.py elimina -r foo Namespace(nomedir='foo', ricorsiva=True)
Fino ad ora gli esempi hammo mostrato semplici flag booleani, opzioni con argomenti stringa o numerici ed argomenti posizionali. argparse supporta anche sofisticate specifiche di argomenti per elenchi di argomenti a lunghezza variabile, enumerazioni e valori costanti.
E' possibile configurare una singola definizione di argomento per consumare argomenti multipli sulla riga di comando mentre vengono elaborati. Occorre impostare nargs ad uno dei flag seguenti, in base al numero di argomenti specificati od attesi:
Valore | Significato |
---|---|
N | Il numero di argomenti assoluto (es. 3) |
? | 0 od 1 argomento |
* | 0 o tutti gli argomenti |
+ | Tutti od almeno un argomento |
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--tre', nargs=3)
parser.add_argument('--opzionale', nargs='?')
parser.add_argument('--tutti', nargs='*', dest='all')
parser.add_argument('--uno-o-piu', nargs='+')
print parser.parse_args()
Il parser applica le istruzioni di conteggio degli argomenti, e genera un accurato diagramma di sintassi come parte del testo di aiuto del comando.
$ python argparse_nargs.py -h usage: argparse_nargs.py [-h] [--tre TRE TRE TRE] [--opzionale [OPZIONALE]] [--tutti [ALL [ALL ...]]] [--uno-o-piu UNO_O_PIU [UNO_O_PIU ...]] optional arguments: -h, --help show this help message and exit --tre TRE TRE TRE --opzionale [OPZIONALE] --tutti [ALL [ALL ...]] --uno-o-piu UNO_O_PIU [UNO_O_PIU ...] $ python argparse_nargs.py Namespace(all=None, opzionale=None, tre=None, uno_o_piu=None) $ python argparse_nargs.py --tre usage: argparse_nargs.py [-h] [--tre TRE TRE TRE] [--opzionale [OPZIONALE]] [--tutti [ALL [ALL ...]]] [--uno-o-piu UNO_O_PIU [UNO_O_PIU ...]] argparse_nargs.py: error: argument --tre: expected 3 argument(s) $ python argparse_nargs.py --tre a b c Namespace(all=None, opzionale=None, tre=['a', 'b', 'c'], uno_o_piu=None) $ python argparse_nargs.py --opzionale Namespace(all=None, opzionale=None, tre=None, uno_o_piu=None) $ python argparse_nargs.py --opzionale con_valore Namespace(all=None, opzionale='con_valore', tre=None, uno_o_piu=None) $ python argparse_nargs.py --tutti con valori multipli Namespace(all=['con', 'valori', 'multipli'], opzionale=None, tre=None, uno_o_piu=None) $ python argparse_nargs.py --tutti con valori multipli Namespace(all=['con', 'valori', 'multipli'], opzionale=None, tre=None, uno_o_piu=None) $ python argparse_nargs.py --uno-o-piu con valori multipli Namespace(all=None, opzionale=None, tre=None, uno_o_piu=['con', 'valori', 'multipli']) $ python argparse_nargs.py --uno-o-piu usage: argparse_nargs.py [-h] [--tre TRE TRE TRE] [--opzionale [OPZIONALE]] [--tutti [ALL [ALL ...]]] [--uno-o-piu UNO_O_PIU [UNO_O_PIU ...]] argparse_nargs.py: error: argument --uno-o-piu: expected at least one argument
argparse
tratta tutti i valori degli argomenti come stringhe, a meno che non gli si dica di convertire la stringa in altro tipo. Il parametro
type
di
add_argument()
è una funzione di conversione utilizzata da
ArgumentParser
per trasformare il valore dell'argomento da stringa a qualche altro tipo.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', type=int)
parser.add_argument('-f', type=float)
parser.add_argument('--file', type=file)
try:
print parser.parse_args()
except IOError, msg:
parser.error(str(msg))
Se la conversione di tipo fallisce, argparse solleva una eccezione. TypeError e ValueError sono intercettate automaticamente e convertite in un semplice messaggio di errore per l'utente. Altre eccezioni, tipo IOError nell'esempio qui sotto, sollevata laddove il file di input non esiste, deve essere gestita dal chiamante.
$ python argparse_type.py -i 1 Namespace(f=None, file=None, i=1) $ python argparse_type.py -f 3.14 Namespace(f=3.14, file=None, i=None) $ python argparse_type.py --file argparse_type.py Namespace(f=None, file=<open file 'argparse_type.py', mode 'r' at 0x7f49e8d32300>, i=None)
Per limitare un argomento in input ad un valore all'interno di un insieme predefinito, si utilizza il parametro choices .
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--modo', choices=('sola-lettura', 'lettura-scrittura'))
print parser.parse_args()
Se l'argomento per
--modo
non è tra quelli consentiti, viene generato un errore e l'elaborazione viene interrotta.
$ python argparse_choices.py -h usage: argparse_choices.py [-h] [--modo {sola-lettura,lettura-scrittura}] optional arguments: -h, --help show this help message and exit --modo {sola-lettura,lettura-scrittura} $ python argparse_choices.py --modo sola-lettura Namespace(modo='sola-lettura') $ python argparse_choices.py --modo lettura-scrittura Namespace(modo='lettura-scrittura') $ python argparse_choices.py --modo accodamento usage: argparse_choices.py [-h] [--modo {sola-lettura,lettura-scrittura}] argparse_choices.py: error: argument --modo: invalid choice: 'accodamento' (choose from 'sola-lettura', 'lettura-scrittura')
Gli oggetti File possano essere istanziati con un solo argomento stringa, tuttavia questo approccio non consente di ottenere la specifica del tipo di accesso. FileType consente un modo più flessibile per specificare che un argomento dovrebbe essere un file, incluso il modo e la dimensione del buffer.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', metavar='file-in-entrata', type=argparse.FileType('rt'))
parser.add_argument('-o', metavar='file-in-uscita', type=argparse.FileType('wt'))
try:
results = parser.parse_args()
print 'File in entrata:', results.i
print 'File in uscita:', results.o
except IOError, msg:
parser.error(str(msg))
Il valore associato al nome dell'argomento è l' handle del file aperto. Il programmatore è responsabile della chiusura del file, una volta terminate le operazioni su di esso.
$ python argparse_FileType.py -h usage: argparse_FileType.py [-h] [-i file-in-entrata] [-o file-in-uscita] optional arguments: -h, --help show this help message and exit -i file-in-entrata -o file-in-uscita $ python argparse_FileType.py -i argparse_FileType.py -o file_temporaneo.txt File in entrata: <open file 'argparse_FileType.py', mode 'rt' at 0x7ff7be56c300> File in uscita: <open file 'file_temporaneo.txt', mode 'wt' at 0x7ff7be56c390> $ python argparse_FileType.py -i file_non_esiste.txt usage: argparse_FileType.py [-h] [-i file-in-entrata] [-o file-in-uscita] argparse_FileType.py: error: argument -i: can't open 'file_non_esiste.txt': [Errno 2] No such file or directory: 'file_non_esiste.txt'
In aggiunta alle azioni
built-in
definite in precedenza, è possibile definire azioni personalizzate fornendo un oggetto che implementi l'API
Action
. L'oggetto passato ad
add_argument()
come
action
dovrebbe ottenere parametri che descrivono l'argomento che si sta definendo e ritornare un oggetto richiamabile che riceve come parametro il
parser
che sta elaborando gli argomenti, lo spazio dei nomi (
namespace
) che conserva i risultati dell'elaborazione, il valore (
value
) dell'argomento sul quale si sta agendo, e la stringa di opzione (
option_string
) che ha fatto partire l'azione.
Una classe
Action
viene fornita come punto di partenza per definire nuove azioni. Il costruttore gestisce la definizione degli argomenti, in modo che si debba solamente sovrascrivere la funzione
__call__()
nella sottoclasse.
import argparse
class AzionePersonalizzata(argparse.Action):
def __init__(self,
option_strings,
dest,
nargs=None,
const=None,
default=None,
type=None,
choices=None,
required=False,
help=None,
metavar=None):
argparse.Action.__init__(self,
option_strings=option_strings,
dest=dest,
nargs=nargs,
const=const,
default=default,
type=type,
choices=choices,
required=required,
help=help,
metavar=metavar,
)
print
print 'Inizializzazione di AzionePersonalizzata'
for name,value in sorted(locals().items()):
if name == 'self' or value is None:
continue
print ' %s = %r' % (name, value)
return
def __call__(self, parser, namespace, values, option_string=None):
print
print 'Elaborazione di AzionePersonalizzata per "%s"' % self.dest
print ' parser = %s' % id(parser)
print ' values = %r' % values
print ' option_string = %r' % option_string
# Do some arbitrary processing of the input values
# Si esegue qualche arbitraria elaborazione dei valori in input
if isinstance(values, list):
values = [ v.upper() for v in values ]
else:
values = values.upper()
# Si salvano i risultati nello spazio dei nomi utilizzando
# la variabile di destinazione passata al costruttore
setattr(namespace, self.dest, values)
parser = argparse.ArgumentParser()
parser.add_argument('-a', action=AzionePersonalizzata)
parser.add_argument('-m', nargs='*', action=AzionePersonalizzata)
parser.add_argument('positional', action=AzionePersonalizzata)
results = parser.parse_args(['-a', 'value', '-m' 'multi-valore', 'valore-posizionale'])
print
print results
Il tipo di valori dipende dal valore di nargs . Se l'argomento consente valori multipli, i valori saranno in una lista anche se si tratta di un singolo valore.
Il valore di
option_string
dipende anche dalla specifica originale degli argomenti. Per argomenti richiesti e posizionali
option_string
è sempre
None
$ python argparse_custom_action.py -h Inizializzazione di AzionePersonalizzata dest = 'a' option_strings = ['-a'] required = False Inizializzazione di AzionePersonalizzata dest = 'm' nargs = '*' option_strings = ['-m'] required = False Inizializzazione di AzionePersonalizzata dest = 'positional' option_strings = [] required = True Elaborazione di AzionePersonalizzata per "a" parser = 139627453637584 values = 'value' option_string = '-a' Elaborazione di AzionePersonalizzata per "m" parser = 139627453637584 values = ['multi-valore'] option_string = '-m' Elaborazione di AzionePersonalizzata per "positional" parser = 139627453637584 values = 'valore-posizionale' option_string = None Namespace(a='VALUE', m=['MULTI-VALORE'], positional='VALORE-POSIZIONALE')
Vedere anche: