Python Language
Analizzare gli argomenti della riga di comando
Ricerca…
introduzione
La maggior parte degli strumenti a riga di comando si basano su argomenti passati al programma al momento dell'esecuzione. Invece di richiedere input, questi programmi si aspettano che vengano impostati dati o flag specifici (che diventano booleani). Ciò consente sia all'utente che ad altri programmi di eseguire il file Python passandogli i dati all'avvio. Questa sezione spiega e dimostra l'implementazione e l'uso degli argomenti della riga di comando in Python.
Ciao mondo in argparse
Il seguente programma dice ciao all'utente. Prende un argomento posizionale, il nome dell'utente e può anche essere detto il saluto.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('name',
help='name of user'
)
parser.add_argument('-g', '--greeting',
default='Hello',
help='optional alternate greeting'
)
args = parser.parse_args()
print("{greeting}, {name}!".format(
greeting=args.greeting,
name=args.name)
)
$ python hello.py --help
usage: hello.py [-h] [-g GREETING] name
positional arguments:
name name of user
optional arguments:
-h, --help show this help message and exit
-g GREETING, --greeting GREETING
optional alternate greeting
$ python hello.py world
Hello, world!
$ python hello.py John -g Howdy
Howdy, John!
Per maggiori dettagli si prega di leggere la documentazione di argparse .
Esempio di base con docopt
docopt trasforma l'argomento della riga di comando in analisi. Invece di analizzare gli argomenti, basta scrivere la stringa di utilizzo per il proprio programma e docopt analizza la stringa di utilizzo e la utilizza per estrarre gli argomenti della riga di comando.
"""
Usage:
script_name.py [-a] [-b] <path>
Options:
-a Print all the things.
-b Get more bees into the path.
"""
from docopt import docopt
if __name__ == "__main__":
args = docopt(__doc__)
import pprint; pprint.pprint(args)
Esecuzioni di esempio:
$ python script_name.py
Usage:
script_name.py [-a] [-b] <path>
$ python script_name.py something
{'-a': False,
'-b': False,
'<path>': 'something'}
$ python script_name.py something -a
{'-a': True,
'-b': False,
'<path>': 'something'}
$ python script_name.py -b something -a
{'-a': True,
'-b': True,
'<path>': 'something'}
Impostazione di argomenti mutuamente esclusivi con argparse
Se vuoi che due o più argomenti si escludano a vicenda. È possibile utilizzare la funzione argparse.ArgumentParser.add_mutually_exclusive_group()
. Nell'esempio seguente, possono esistere foo o bar ma non entrambi allo stesso tempo.
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-f", "--foo")
group.add_argument("-b", "--bar")
args = parser.parse_args()
print "foo = ", args.foo
print "bar = ", args.bar
Se si tenta di eseguire lo script specificando entrambi --bar
argomenti --foo
e --bar
, lo script si lamenterà con il messaggio seguente.
error: argument -b/--bar: not allowed with argument -f/--foo
Utilizzo degli argomenti della riga di comando con argv
Ogni volta che uno script Python viene richiamato dalla riga di comando, l'utente può fornire ulteriori argomenti della riga di comando che verranno passati allo script. Questi argomenti saranno disponibili per il programmatore dalla variabile di sistema sys.argv
("argv" è un nome tradizionale utilizzato nella maggior parte dei linguaggi di programmazione e significa " arg ument v ector").
Per convenzione, il primo elemento nell'elenco sys.argv
è il nome dello stesso script Python, mentre il resto degli elementi sono i token passati dall'utente quando si richiama lo script.
# cli.py
import sys
print(sys.argv)
$ python cli.py
=> ['cli.py']
$ python cli.py fizz
=> ['cli.py', 'fizz']
$ python cli.py fizz buzz
=> ['cli.py', 'fizz', 'buzz']
Ecco un altro esempio di come usare argv
. Prima rimuoviamo l'elemento iniziale di sys.argv perché contiene il nome dello script. Quindi combiniamo il resto degli argomenti in una singola frase e infine stampiamo quella frase anteponendo il nome dell'utente attualmente loggato (in modo che emuli un programma di chat).
import getpass
import sys
words = sys.argv[1:]
sentence = " ".join(words)
print("[%s] %s" % (getpass.getuser(), sentence))
L'algoritmo comunemente usato quando "manualmente" l'analisi di un numero di argomenti non posizionali è quello di scorrere l'elenco sys.argv
. Un modo è quello di andare oltre la lista e pop ogni elemento di esso:
# reverse and copy sys.argv
argv = reversed(sys.argv)
# extract the first element
arg = argv.pop()
# stop iterating when there's no more args to pop()
while len(argv) > 0:
if arg in ('-f', '--foo'):
print('seen foo!')
elif arg in ('-b', '--bar'):
print('seen bar!')
elif arg in ('-a', '--with-arg'):
arg = arg.pop()
print('seen value: {}'.format(arg))
# get the next value
arg = argv.pop()
Messaggio di errore del parser personalizzato con argparse
È possibile creare messaggi di errore parser in base alle esigenze del proprio script. Questo è attraverso la funzione argparse.ArgumentParser.error
. L'esempio seguente mostra lo script stampa di un utilizzo e un messaggio di errore a stderr
quando --foo
è dato, ma non --bar
.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--foo")
parser.add_argument("-b", "--bar")
args = parser.parse_args()
if args.foo and args.bar is None:
parser.error("--foo requires --bar. You did not specify bar.")
print "foo =", args.foo
print "bar =", args.bar
Supponendo che il nome dello script sia sample.py, eseguiamo: python sample.py --foo ds_in_fridge
Lo script si lamenterà con quanto segue:
usage: sample.py [-h] [-f FOO] [-b BAR]
sample.py: error: --foo requires --bar. You did not specify bar.
Raggruppamento concettuale di argomenti con argparse.add_argument_group ()
Quando crei Argparse ArgumentParser () ed esegui il tuo programma con '-h' ottieni un messaggio di utilizzo automatico che spiega quali argomenti puoi eseguire con il tuo software. Per impostazione predefinita, gli argomenti posizionali e gli argomenti condizionali sono separati in due categorie, ad esempio, qui c'è un piccolo script (example.py) e l'output quando si esegue python example.py -h
.
import argparse
parser = argparse.ArgumentParser(description='Simple example')
parser.add_argument('name', help='Who to greet', default='World')
parser.add_argument('--bar_this')
parser.add_argument('--bar_that')
parser.add_argument('--foo_this')
parser.add_argument('--foo_that')
args = parser.parse_args()
usage: example.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
[--foo_this FOO_THIS] [--foo_that FOO_THAT]
name
Simple example
positional arguments:
name Who to greet
optional arguments:
-h, --help show this help message and exit
--bar_this BAR_THIS
--bar_that BAR_THAT
--foo_this FOO_THIS
--foo_that FOO_THAT
Ci sono alcune situazioni in cui vuoi separare i tuoi argomenti in ulteriori sezioni concettuali per aiutare il tuo utente. Ad esempio, potresti desiderare di avere tutte le opzioni di input in un gruppo e tutte le opzioni di output in un'altra. L'esempio sopra può essere regolato per separare gli --foo_*
dagli argomenti --bar_*
modo.
import argparse
parser = argparse.ArgumentParser(description='Simple example')
parser.add_argument('name', help='Who to greet', default='World')
# Create two argument groups
foo_group = parser.add_argument_group(title='Foo options')
bar_group = parser.add_argument_group(title='Bar options')
# Add arguments to those groups
foo_group.add_argument('--bar_this')
foo_group.add_argument('--bar_that')
bar_group.add_argument('--foo_this')
bar_group.add_argument('--foo_that')
args = parser.parse_args()
Che produce questo output quando python example.py -h
viene eseguito:
usage: example.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
[--foo_this FOO_THIS] [--foo_that FOO_THAT]
name
Simple example
positional arguments:
name Who to greet
optional arguments:
-h, --help show this help message and exit
Foo options:
--bar_this BAR_THIS
--bar_that BAR_THAT
Bar options:
--foo_this FOO_THIS
--foo_that FOO_THAT
Esempio avanzato con docopt e docopt_dispatch
Come con docopt, con [docopt_dispatch] costruisci il tuo --help
nella variabile __doc__
del tuo modulo entry-point. Lì, si chiama dispatch
con la stringa doc come argomento, quindi può eseguire il parser su di esso.
Fatto questo, invece di gestire manualmente gli argomenti (che di solito finiscono in una struttura ciclomatic se / else alta), lo si lascia alla distribuzione dando solo come si desidera gestire l'insieme di argomenti.
Questo è il motivo per cui è utilizzato il decoratore dispatch.on
: gli si fornisce l'argomento o la sequenza di argomenti che devono attivare la funzione e tale funzione verrà eseguita con i valori corrispondenti come parametri.
"""Run something in development or production mode.
Usage: run.py --development <host> <port>
run.py --production <host> <port>
run.py items add <item>
run.py items delete <item>
"""
from docopt_dispatch import dispatch
@dispatch.on('--development')
def development(host, port, **kwargs):
print('in *development* mode')
@dispatch.on('--production')
def development(host, port, **kwargs):
print('in *production* mode')
@dispatch.on('items', 'add')
def items_add(item, **kwargs):
print('adding item...')
@dispatch.on('items', 'delete')
def items_delete(item, **kwargs):
print('deleting item...')
if __name__ == '__main__':
dispatch(__doc__)