Si voleva un semplice esempio di argparse: 1 argomento, 3 risultati


529

La documentazione per il modulo Python Argparse , sebbene sia eccellente, è troppo per essere afferrata dal mio piccolo cervello da principiante in questo momento. Non ho bisogno di fare matematica sulla riga di comando o immischiarmi con le righe di formattazione sullo schermo o cambiare i caratteri delle opzioni. Tutto quello che voglio fare è "Se arg è A, fallo, se B lo fa, se nessuno dei precedenti mostra aiuto ed esci" .


15
quindi controlla solo sys.argvl'argomento che desideri ...
JBernardo,

10
Hai mai provato plac ? È un wrapper facile da usare su argparse con un'ottima documentazione .
Kirbyfan64sos,

157
non sei tu. è argparse. sta cercando di portarti in un viaggio verso le stelle e non gli importa dove stavi andando.
Florian Heigl,

11
Ancora pazze API "pythonic": /
mlvljr il

69
Benedici il tuo matt wilkie, per difenderti da piccoli cervelli principianti ovunque.
polka,

Risposte:


255

La mia comprensione della domanda originale è duplice. In primo luogo, in termini del più semplice esempio argparse possibile, sono sorpreso di non averlo visto qui. Naturalmente, per essere estremamente semplice, è anche tutto sovraccarico con poca potenza, ma potrebbe iniziare.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("a")
args = parser.parse_args()

if args.a == 'magic.name':
    print 'You nailed it!'

Ma questo argomento posizionale è ora richiesto. Se lo lasci fuori quando invochi questo programma, riceverai un errore su argomenti mancanti. Questo mi porta alla seconda parte della domanda originale. Matt Wilkie sembra voler un singolo argomento opzionale senza un'etichetta denominata (le etichette --option). Il mio suggerimento sarebbe di modificare il codice sopra come segue:

...
parser.add_argument("a", nargs='?', default="check_string_for_empty")
...
if args.a == 'check_string_for_empty':
    print 'I can tell that no argument was given and I can deal with that here.'
elif args.a == 'magic.name':
    print 'You nailed it!'
else:
    print args.a

Potrebbe esserci una soluzione più elegante, ma funziona ed è minimalista.


4
Dopo un po 'di tempo a riflettere, concludo che questa domanda in realtà risponde meglio alla Q come chiesto e alla situazione in cui mi trovavo in quel momento. Le altre eccellenti risposte hanno raccolto più che sufficienti rappresentanti per dimostrare il loro valore e possono sopportare una piccola competizione. :-)
matt wilkie,

@badnack: è quello che vuoi che sia, qualunque sia la "a". Se ti aspetti un argomento, ad esempio un nome file, è quello che è stato inserito come nome file nella riga di comando. È quindi possibile eseguire la propria elaborazione per determinare se esiste nel filesystem, ma questa è un'altra domanda e risposta.
poderoso

363

Ecco il modo in cui lo faccio argparse(con più argomenti):

parser = argparse.ArgumentParser(description='Description of your program')
parser.add_argument('-f','--foo', help='Description for foo argument', required=True)
parser.add_argument('-b','--bar', help='Description for bar argument', required=True)
args = vars(parser.parse_args())

args sarà un dizionario contenente gli argomenti:

if args['foo'] == 'Hello':
    # code here

if args['bar'] == 'World':
    # code here

Nel tuo caso aggiungi semplicemente un solo argomento.


3
come menzionato nel mio commento all'altra risposta, mi piacerebbe mantenere la formattazione automatica della guida di argparse, ma non sembra esserci un'opzione per avere un argomento senza nome (più probabilmente non capisco appena lo vedo ), ad esempio, bisogna fare foo.py --action installo foo.py --action removeinvece di semplicementefoo.py install
matt wilkie,

7
@mattwilkie Quindi devi definire un argomento posizionale come questo: parser.add_argument('install', help='Install the app') (Nota che non puoi definire un argomento posizionale con required=True)
Diego Navarro,

32
Come noob di argparse, questa risposta mi è stata di grande aiuto perché non sapevo dove trovare le opzioni dopo che erano state passate . In altre parole, avevo bisogno di capire come il argsdict è stato generato come sopra.
Mr.Kelley,

3
Utilizzare la "forma breve" quando si chiama il programma direttamente dalla riga di comando e la "forma lunga" quando si esegue un programma / comando all'interno di uno script. In tal caso è più leggibile dall'uomo con la forma lunga e quindi più facile seguire la logica del codice / script.
ola,

17
Personalmente trovo più pulito accedere agli argomenti come args.fooe args.barinvece della sintassi del dizionario. In ogni caso va bene ovviamente, ma args non è in realtà un dizionario ma un argparse.Namespaceoggetto.
Michael Mior,

210

La argparsedocumentazione è abbastanza buona, ma tralascia alcuni dettagli utili che potrebbero non essere ovvi. (@Diego Navarro ne ha già parlato in parte ma cercherò di espandere leggermente la sua risposta.) L'utilizzo di base è il seguente:

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--my-foo', default='foobar')
parser.add_argument('-b', '--bar-value', default=3.14)
args = parser.parse_args()

L'oggetto da cui si ottiene parse_args()è un oggetto "Spazio dei nomi": un oggetto le cui variabili membro prendono il nome dagli argomenti della riga di comando. L' Namespaceoggetto è il modo in cui accedi ai tuoi argomenti e ai valori ad essi associati:

args = parser.parse_args()
print args.my_foo
print args.bar_value

(Nota che argparsesostituisce '-' nei nomi degli argomenti con caratteri di sottolineatura quando si nominano le variabili.)

In molte situazioni potresti voler usare argomenti semplicemente come flag che non hanno valore. Puoi aggiungerli in argparse in questo modo:

parser.add_argument('--foo', action='store_true')
parser.add_argument('--no-foo', action='store_false')

Quanto sopra creerà le variabili denominate 'pippo' con valore Vero e 'no_foo' con valore Falso, rispettivamente:

if (args.foo):
    print "foo is true"

if (args.no_foo is False):
    print "nofoo is false"

Si noti inoltre che è possibile utilizzare l'opzione "obbligatorio" quando si aggiunge un argomento:

parser.add_argument('-o', '--output', required=True)

In questo modo se ometti questo argomento dalla riga di comando argparseti dirà che è mancante e interrompi l'esecuzione del tuo script.

Infine, nota che è possibile creare una struttura dettata dei tuoi argomenti usando la varsfunzione, se ciò ti semplifica la vita.

args = parser.parse_args()
argsdict = vars(args)
print argsdict['my_foo']
print argsdict['bar_value']

Come puoi vedere, varsrestituisce un dict con i nomi degli argomenti come chiavi e i loro valori come, er, valori.

Ci sono molte altre opzioni e cose che puoi fare, ma questo dovrebbe coprire gli scenari di utilizzo più essenziali e comuni.


3
Qual è il punto di '-f'e '-b'? Perché non puoi ometterlo?
user2763361

13
È abbastanza convenzionale avere sia una versione 'short form' (un trattino) che 'long form' (due trattini) per ogni opzione di runtime. Vedrai questo, per esempio, in quasi tutte le utility standard Unix / Linux; fai un man cpo man lse scoprirai che molte opzioni sono disponibili in entrambi i gusti (ad es -f, --force.). Probabilmente ci sono molte ragioni per cui le persone preferiscono l'una o l'altra, ma in ogni caso è abbastanza standard rendere entrambi i moduli disponibili nel tuo programma.
DMH,

59

Matt sta chiedendo dei parametri posizionali in argparse, e sono d'accordo che la documentazione di Python manchi su questo aspetto. Non c'è un singolo esempio completo nelle ~ 20 pagine dispari che mostra sia l' analisi che l'utilizzo dei parametri posizionali .

Nessuna delle altre risposte qui mostra un esempio completo di parametri posizionali, quindi ecco un esempio completo:

# tested with python 2.7.1
import argparse

parser = argparse.ArgumentParser(description="An argparse example")

parser.add_argument('action', help='The action to take (e.g. install, remove, etc.)')
parser.add_argument('foo-bar', help='Hyphens are cumbersome in positional arguments')

args = parser.parse_args()

if args.action == "install":
    print("You asked for installation")
else:
    print("You asked for something other than installation")

# The following do not work:
# print(args.foo-bar)
# print(args.foo_bar)

# But this works:
print(getattr(args, 'foo-bar'))

La cosa che mi ha buttato fuori è che argparse convertirà l'argomento denominato "--foo-bar" in "foo_bar", ma un parametro posizionale chiamato "foo-bar" rimane come "foo-bar", rendendo meno ovvio come usalo nel tuo programma.

Nota le due righe vicino alla fine del mio esempio: nessuna di queste funzionerà per ottenere il valore del parametro posizionale foo-bar. Il primo è ovviamente sbagliato (è un'espressione aritmetica args.foo meno la barra), ma il secondo non funziona neanche:

AttributeError: 'Namespace' object has no attribute 'foo_bar'

Se vuoi usare l' foo-barattributo, devi usare getattr, come visto nell'ultima riga del mio esempio. La cosa folle è che se si provasse a utilizzare dest=foo_barper modificare il nome della proprietà in qualcosa di più facile accesso, si otterrebbe un messaggio di errore davvero bizzarro:

ValueError: dest supplied twice for positional argument

Ecco come viene eseguito l'esempio sopra:

$ python test.py
usage: test.py [-h] action foo-bar
test.py: error: too few arguments

$ python test.py -h
usage: test.py [-h] action foo-bar

An argparse example

positional arguments:
  action      The action to take (e.g. install, remove, etc.)
  foo-bar     Hyphens are cumbersome in positional arguments

optional arguments:
  -h, --help  show this help message and exit

$ python test.py install foo
You asked for installation
foo

5
nargs='?'è l'incantesimo di una "posizionale optional" come da stackoverflow.com/questions/4480075/...
MarkHu

Il fatto che una posizione foo-barnon venga trasformata foo_barviene affrontato in bugs.python.org/issue15125 .
hpaulj,

2
Penso che una soluzione più semplice per questo bug sia semplicemente chiamare l'argomento "foo_bar" invece di "foo-bar", quindi print args.foo_barfunziona. Poiché è un argomento posizionale, non è necessario specificare il nome quando si chiama lo script, quindi non importa per l'utente.
Luator,

@luator Hai ragione, è facile rinominare l'argomento, ma l'autore della segnalazione di bug sostiene che si tratta ancora di un malfunzionamento a causa del carico cognitivo non necessario. Quando si utilizza argparse, è necessario mettere in pausa e richiamare le diverse convenzioni di denominazione per opzioni e argomenti. Vedi bugs.python.org/msg164968 .
Mark E. Haase,

1
@mehaase Sono totalmente d'accordo sul fatto che si tratti di un malfunzionamento che dovrebbe essere corretto. Penso solo che rinominare l'argomento sia la soluzione più semplice e meno confusa rispetto al dover usare getattr(è anche più flessibile in quanto consente di cambiare un argomento da facoltativo a posizionale senza dover cambiare il codice che utilizza il valore).
Luator,

22

Ennesima introduzione sintetica, ispirata a questo post .

import argparse

# define functions, classes, etc.

# executes when your script is called from the command-line
if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    #
    # define each option with: parser.add_argument
    #
    args = parser.parse_args() # automatically looks at sys.argv
    #
    # access results with: args.argumentName
    #

Gli argomenti sono definiti con combinazioni di quanto segue:

parser.add_argument( 'name', options... )              # positional argument
parser.add_argument( '-x', options... )                # single-char flag
parser.add_argument( '-x', '--long-name', options... ) # flag with long name

Le opzioni comuni sono:

  • aiuto : descrizione di questo argomento quando --helpviene utilizzato.
  • default : valore predefinito se l'arg viene omesso.
  • tipo : se ti aspetti un floato int(altrimenti è str).
  • dest : assegna un nome diverso a una bandiera (ad es '-x', '--long-name', dest='longName'.).
    Nota: per impostazione predefinita --long-namesi accede conargs.long_name
  • azione : per la gestione speciale di determinati argomenti
    • store_true, store_false: per arg booleani
      '--foo', action='store_true' => args.foo == True
    • store_const: da utilizzare con l'opzioneconst
      '--foo', action='store_const', const=42 => args.foo == 42
    • count: per opzioni ripetute, come in./myscript.py -vv
      '-v', action='count' => args.v == 2
    • append: per opzioni ripetute, come in./myscript.py --foo 1 --foo 2
      '--foo', action='append' => args.foo == ['1', '2']
  • richiesto : se è richiesto un flag o un argomento posizionale no.
  • nargs : affinché una bandiera catturi N args
    ./myscript.py --foo a b => args.foo = ['a', 'b']
  • scelte : per limitare possibili input (specificare come elenco di stringhe o ints se type=int).

12

Nota il Tutorial Argparse negli HOWTO di Python . Si parte dalla maggior parte degli esempi di base, come questo:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)

e passa a quelli meno elementari.

C'è un esempio con una scelta predefinita per un'opzione, come quello che viene chiesto:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
                    help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
    print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
    print("{}^2 == {}".format(args.square, answer))
else:
    print(answer)

È bello vedere che i documenti sono stati aggiornati. Ti assicuro che non è stato così quando OP ha pubblicato la domanda 5 anni fa.
ntwrkguru,

10

Ecco cosa mi è venuto in mente nel mio progetto di apprendimento grazie principalmente a @DMH ...

Codice demo:

import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f', '--flag', action='store_true', default=False)  # can 'store_false' for no-xxx flags
    parser.add_argument('-r', '--reqd', required=True)
    parser.add_argument('-o', '--opt', default='fallback')
    parser.add_argument('arg', nargs='*') # use '+' for 1 or more args (instead of 0 or more)
    parsed = parser.parse_args()
    # NOTE: args with '-' have it replaced with '_'
    print('Result:',  vars(parsed))
    print('parsed.reqd:', parsed.reqd)

if __name__ == "__main__":
    main()

Potrebbe essersi evoluto ed è disponibile online: command-line.py

Script per dare a questo codice un allenamento: command-line-demo.sh


2
Finalmente un esempio argparse che ha un senso
opentokix

5

Puoi anche usare plac (un involucro intorno argparse).

Come bonus genera istruzioni di aiuto ordinate - vedi sotto.

Script di esempio:

#!/usr/bin/env python3
def main(
    arg: ('Argument with two possible values', 'positional', None, None, ['A', 'B'])
):
    """General help for application"""
    if arg == 'A':
        print("Argument has value A")
    elif arg == 'B':
        print("Argument has value B")

if __name__ == '__main__':
    import plac
    plac.call(main)

Esempio di output:

Nessun argomento fornito - example.py :

usage: example.py [-h] {A,B}
example.py: error: the following arguments are required: arg

Argomento imprevisto fornito - example.py C :

usage: example.py [-h] {A,B}
example.py: error: argument arg: invalid choice: 'C' (choose from 'A', 'B')

Argomento corretto fornito - example.py A :

Argument has value A

Menu di aiuto completo (generato automaticamente) - example.py -h :

usage: example.py [-h] {A,B}

General help for application

positional arguments:
  {A,B}       Argument with two possible values

optional arguments:
  -h, --help  show this help message and exit

Breve spiegazione:

Il nome dell'argomento di solito è uguale al nome del parametro ( arg).

L'annotazione tupla dopo il argparametro ha il seguente significato:

  • Descrizione ( Argument with two possible values)
  • Tipo di argomento - uno di 'flag', 'opzione' o 'posizionale' ( positional)
  • Abbreviazione ( None)
  • Tipo di valore dell'argomento - ad es. float, string ( None)
  • Insieme limitato di scelte ( ['A', 'B'])

Documentazione:

Per saperne di più sull'uso di plac, consulta la sua ottima documentazione:

Plac: analisi della riga di comando in modo semplice


4

Per aggiungere ciò che altri hanno affermato:

Di solito mi piace usare il parametro 'dest' per specificare un nome di variabile e quindi usare 'globals (). Update ()' per mettere quelle variabili nello spazio dei nomi globale.

Uso:

$ python script.py -i "Hello, World!"

Codice:

...
parser.add_argument('-i', '--input', ..., dest='inputted_variable',...)
globals().update(vars(parser.parse_args()))
...
print(inputted_variable) # Prints "Hello, World!"

argparseUtilizza internamente getattre setattrper accedere ai valori nello spazio dei nomi. In questo modo non è infastidito da destvalori stranamente formati .
hpaulj,

1

Un modo davvero semplice di utilizzare argparse e modificare le opzioni '-h' / '--help' per visualizzare le istruzioni di aiuto del proprio codice personale è impostare l'aiuto predefinito su False, è inoltre possibile aggiungere tutti gli altri .add_arguments che si desidera :

import argparse

parser = argparse.ArgumentParser(add_help=False)

parser.add_argument('-h', '--help', action='help',
                help='To run this script please provide two arguments')
parser.parse_args()

Esegui: python test.py -h

Produzione:

usage: test.py [-h]

optional arguments:
  -h, --help  To run this script please provide two arguments

-1

La risposta più semplice!

PS chi ha scritto il documento di argparse è sciocco

codice Python:

import argparse
parser = argparse.ArgumentParser(description='')
parser.add_argument('--o_dct_fname',type=str)
parser.add_argument('--tp',type=str)
parser.add_argument('--new_res_set',type=int)
args = parser.parse_args()
o_dct_fname = args.o_dct_fname
tp = args.tp
new_res_set = args.new_res_set

codice corrente

python produce_result.py --o_dct_fname o_dct --tp father_child --new_res_set 1

Questa risposta non aggiunge nulla di nuovo / diverso rispetto alle risposte esistenti.
NVS Abhilash,

sono il più chiaro, parlare è economico, mostra il codice
gouxute il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.