2013-01-02 8 views
83

Il titolo riassume in sostanza ciò che mi piacerebbe accadere.In Python, usando argparse, consenti solo interi positivi

Ecco cosa ho, e mentre il programma non esplode su un numero intero non intenzionale, voglio che l'utente sia informato che un intero non intenzionale è fondamentalmente privo di senso.

import argparse 
parser = argparse.ArgumentParser() 
parser.add_argument("-g", "--games", type=int, default=162, 
        help="The number of games to simulate") 
args = parser.parse_args() 

E l'output:

python simulate_many.py -g 20 
Setting up... 
Playing games... 
.................... 

uscita con un valore negativo:

python simulate_many.py -g -2 
Setting up... 
Playing games... 

Ora, ovviamente potrei solo aggiungere un caso per determinare if args.games è negativo, ma ero curioso di sapere se c'era un modo per intrappolarlo al livello argparse, in modo da sfruttare la stampa automatica.

Idealmente, sarebbe stampare qualcosa di simile a questo:

python simulate_many.py -g a 
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE] 
simulate_many.py: error: argument -g/--games: invalid int value: 'a' 

Come così:

python simulate_many.py -g -2 
usage: simulate_many.py [-h] [-g GAMES] [-d] [-l LEAGUE] 
simulate_many.py: error: argument -g/--games: invalid positive int value: '-2' 

Per ora sto facendo questo, e credo di essere felice:

if args.games <= 0: 
    parser.print_help() 
    print "-g/--games: must be positive." 
    sys.exit(1) 

risposta

120

Questo dovrebbe essere possibile utilizzando type. Avrai ancora bisogno di definire un metodo effettivo che decide questo per voi:

def check_positive(value): 
    ivalue = int(value) 
    if ivalue <= 0: 
     raise argparse.ArgumentTypeError("%s is an invalid positive int value" % value) 
    return ivalue 

parser = argparse.ArgumentParser(...) 
parser.add_argument('foo', type=check_positive) 

Questo è fondamentalmente solo un esempio tratto dal funzione perfect_square nel docs su argparse.

+1

vostra funzione può avere più valori? Come funziona? – Tom

+0

Se la conversione in 'int' fallisce, ci sarà comunque un output leggibile? O dovresti 'provare' 'aumentare' la conversione manualmente per quello? – NOhs

+2

@MrZ Fornirà qualcosa come 'errore: argomento foo: valore check_positive non valido: 'foo = ''. Potresti semplicemente aggiungere un 'try:' ... 'ad eccezione di ValueError:' attorno ad esso che genera nuovamente un'eccezione con un messaggio di errore migliore. – Yuushi

3

Il modo più rapido e sporco, se si dispone di un massimo prevedibile così come min per il vostro arg, è utilizzare choices con una gamma

parser.add_argument('foo', type=int, choices=xrange(0, 1000)) 
+12

Il lato negativo è l'uscita orribile. – jgritty

+3

enfasi su _dirty_, credo. –

+2

Per essere più chiari sul punto di jgritty, choices = xrange (0,1000) comporterà che l'intera lista di numeri interi da 1 a 999 inclusi venga scritta sulla tua console ogni volta che usi --help o se viene fornito un argomento non valido. Non è una buona scelta nella maggior parte delle circostanze. – biomiker

36

type sarebbe l'opzione consigliata per gestire condizioni/controlli, come nella risposta di Yuushi.

Nel tuo caso specifico, è possibile anche utilizzare il parametro choices se il limite superiore è anche conosciuto:

parser.add_argument('foo', type=int, choices=xrange(5, 10)) 
+2

Immagino che questo sarebbe abbastanza inefficiente, come si genererebbe un intervallo e quindi in bicicletta convalida il tuo input. Un rapido 'se' è molto più veloce. – TravisThomas

+2

@ trav1th In effetti potrebbe essere, ma è un esempio di utilizzo dai documenti. Inoltre, ho detto nella mia risposta che la risposta di Yuushi è quella per cui andare. Buono a dare opzioni. E nel caso di argparse, succede una volta per esecuzione, usa un generatore ('xrange') e non richiede codice aggiuntivo. Questo trade-off è disponibile. Fino a ciascuno per decidere quale strada da percorrere. – aneroid

+9

Per essere più chiari sul punto di jgritty su ben la risposta dell'autore, choices = xrange (0,1000) risulterà nell'intero elenco di numeri interi compresi tra 1 e 999 inclusi nella tua console ogni volta che usi --help o se un argomento non valido è fornito. Non è una buona scelta nella maggior parte delle circostanze. – biomiker

2

un'alternativa più semplice, soprattutto se sottoclasse argparse.ArgumentParser, è quello di avviare la convalida da dentro il metodo parse_args .

All'interno di un tale sottoclasse:

def parse_args(self, args=None, namespace=None): 
    """Parse and validate args.""" 
    namespace = super().parse_args(args, namespace) # super() works in Python 3 
    if namespace.games <= 0: 
     raise self.error('The number of games must be a positive integer.') 
    return namespace 

Questa tecnica non può essere freddo come un callable personalizzato, ma non il lavoro.


Circa ArgumentParser.error(message):

This method prints a usage message including the message to the standard error and terminates the program with a status code of 2.


credito: answer by jonatan