2014-06-12 1 views
90

Uso il seguente codice semplice per analizzare alcuni argomenti; si noti che è richiesto uno di questi. Sfortunatamente, quando l'utente esegue lo script senza fornire l'argomento, il testo di utilizzo/guida visualizzato non indica che esiste un argomento non facoltativo, che trovo molto confuso. Come posso ottenere python per indicare che un argomento non è facoltativo?Argparse: argomenti richiesti elencati in "argomenti facoltativi"?

Ecco il codice:

import argparse 
if __name__ == '__main__': 
    parser = argparse.ArgumentParser(
     description='Foo') 
    parser.add_argument('-i','--input', help='Input file name', required=True) 
    parser.add_argument('-o','--output', help='Output file name', default="stdout") 
    args = parser.parse_args() 
    print ("Input file: %s" % args.input) 
    print ("Output file: %s" % args.output) 

Quando si esegue sopra il codice senza fornire l'argomento obbligatorio, ottengo il seguente output:

usage: foo.py [-h] -i INPUT [-o OUTPUT] 

Foo 

optional arguments: 
    -h, --help   show this help message and exit 
    -i INPUT, --input INPUT 
          Input file name 
    -o OUTPUT, --output OUTPUT 
          Output file name 
+2

In linea di utilizzo, la parte '-i INPUT' non è circondato da parentesi quadre, che indica che sottigliezza è infatti richiesto.Inoltre, puoi spiegarlo manualmente tramite il parametro 'help' –

+1

@JaimeRGP Sì, ma questo non è sufficiente, ovviamente, ed è anche meno importante. Il nome di gruppo assegnato 'argomenti facoltativi' per gli argomenti richiesti è ancora fuorviante. –

risposta

134

parametri di partenza con - o -- sono generalmente considerati opzionali. Tutti gli altri parametri sono parametri posizionali e come tali richiesti dalla progettazione (come gli argomenti delle funzioni posizionali). È possibile richiedere argomenti opzionali, ma questo è un po 'contro il loro design. Poiché fanno ancora parte degli argomenti non posizionali, saranno comunque elencati sotto l'intestazione confondente "argomenti opzionali" anche se sono richiesti. Le parentesi quadre mancanti nella parte di utilizzo mostrano tuttavia che sono effettivamente necessarie.

Vedere anche il documentation:

In generale, il modulo argparse assume che le bandiere come -f e --bar indicano argomenti facoltativi, che può sempre essere omessa alla linea di comando.

Nota: Le opzioni necessarie sono generalmente considerate di cattiva forma in quanto gli utenti si aspettano che le opzioni siano opzionali e, pertanto, dovrebbero essere evitate quando possibile.

Detto, le intestazioni “argomenti posizionali” e “argomenti facoltativi” nella guida sono generati da due gruppi di argomenti in cui gli argomenti vengono separati automaticamente. Ora potresti "hackerarlo" e cambiare il nome di quelli facoltativi, ma una soluzione molto più elegante sarebbe creare un altro gruppo per "argomenti con nome richiesto" (o qualsiasi altra cosa tu voglia chiamarli):

parser = argparse.ArgumentParser(description='Foo') 
parser.add_argument('-o', '--output', help='Output file name', default='stdout') 
requiredNamed = parser.add_argument_group('required named arguments') 
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True) 
parser.parse_args(['-h']) 
usage: [-h] [-o OUTPUT] -i INPUT 

Foo 

optional arguments: 
    -h, --help   show this help message and exit 
    -o OUTPUT, --output OUTPUT 
         Output file name 

required named arguments: 
    -i INPUT, --input INPUT 
         Input file name 
+3

Il rapporto bug pertinente: http://bugs.python.org/issue9694. Definire i propri gruppi di argomenti è la soluzione migliore ora e il prossimo futuro. – hpaulj

+0

A questo punto sembra che l'accesso al valore dell'argomento non funzioni più con 'parse_args()' – frlan

+0

@frlan Cosa intendi? Se chiami per es. 'parser.parse_args (['- i', 'Foo'])' si ottiene comunque un namespace con una proprietà di input che contiene ''Foo'' come valore. – poke

23

Dal momento preferisco elencare argomenti richiesti prima di optional, ho incidere intorno tramite:

parser = argparse.ArgumentParser() 
    parser._action_groups.pop() 
    required = parser.add_argument_group('required arguments') 
    optional = parser.add_argument_group('optional arguments') 
    required.add_argument('--required_arg') 
    optional.add_argument('--optional_arg') 
    return parser.parse_args() 

e queste uscite:

usage: main.py [-h] [--required_arg REQUIRED_ARG] 
       [--optional_arg OPTIONAL_ARG] 

required arguments: 
    --required_arg REQUIRED_ARG 

optional arguments: 
    --optional_arg OPTIONAL_ARG 

Posso vivere senza "help" visualizzato nel gruppo di argomenti facoltativo.

+0

Questo in realtà impone a argparse di trattare qualsiasi argomento come richiesto? – Anthony

+3

Penso che l'argomento 'obbligatorio' debba ancora essere impostato quando si aggiunge un argomento. –

+0

È davvero bello. –

13

Costruzione off di @Karl Rosaen

parser = argparse.ArgumentParser() 
optional = parser._action_groups.pop() # Edited this line 
required = parser.add_argument_group('required arguments') 
# remove this line: optional = parser... 
required.add_argument('--required_arg') 
optional.add_argument('--optional_arg') 
parser._action_groups.append(optional) # added this line 
return parser.parse_args() 

e questo uscite:

usage: main.py [-h] [--required_arg REQUIRED_ARG] 
      [--optional_arg OPTIONAL_ARG] 

required arguments: 
    --required_arg REQUIRED_ARG 

optional arguments: 
    -h, --help     show this help message and exit 
    --optional_arg OPTIONAL_ARG 
+1

BTW, ci sono modi (metodi) come accedere a '_action_group' senza accedere ad un membro protetto? Nel mio caso ho bisogno di aggiungere alcuni argomenti al gruppo già esistente (personalizzato). – machin

+0

Questo è fantastico. Risolve l'elemento - help che compare in un secondo elenco opzionale. – Jeremy