2013-01-02 7 views
83

Tytuł w dużym stopniu podsumowuje to, co chciałbym mieć.W języku Python, używając argparse, zezwól tylko na liczby całkowite dodatnie

Oto, co mam, a podczas gdy program nie wysadzi w powietrze nieprzypominającej liczby całkowitej, chcę, aby użytkownik został poinformowany, że niepozycyjna liczba całkowita jest w zasadzie nonsensem.

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() 

a wyjście:

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

Wyjście z ujemnym:

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

Teraz, oczywiście mogę tylko dodać if w celu ustalenia if args.games jest ujemny, ale byłem ciekaw, czy istniał sposób na uwięzienie go na poziomie argparse, aby skorzystać z automatycznego drukowania użytkowania.

Idealnie byłoby wydrukować coś podobnego do tego:

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' 

tak:

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' 

Na razie robię to, i myślę, że jestem szczęśliwa:

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

Odpowiedz

120

To powinno być możliwe przy użyciu type. Nadal musisz zdefiniować rzeczywisty sposób, który decyduje za nas:

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) 

Jest to w zasadzie tylko dostosowany przykład z funkcji w docs na argparseperfect_square.

+1

Czy czynność mają wiele wartości? Jak to działa? – Tom

+0

Jeśli konwersja na 'int' nie powiedzie się, czy nadal będzie możliwe do odczytania wyjście? A może "spróbuj" ręcznie podnieść 'konwersję? – NOhs

+2

@MrZ To da coś takiego jak: "error: argument foo: invalid check_positive value: 'foo = ". Można by po prostu dodać 'try:' ... 'z wyjątkiem ValueError:' wokół niego, który ponownie podnosi wyjątek z lepszym komunikatem o błędzie. – Yuushi

3

Szybki i brudny sposób, jeśli masz przewidywalny max jak również min dla arg, to użyć choices z zakresu

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

Wadą jest ohydne wyjście. – jgritty

+3

nacisk na _dirty_, chyba. –

+2

Aby być bardziej zrozumiałym odnośnie punktu jgritty, choice = xrange (0,1000) spowoduje, że cała lista liczb całkowitych od 1 do 999 włącznie zostanie zapisana na konsoli za każdym razem, gdy użyjesz opcji --help lub jeśli podano niepoprawny argument. W większości przypadków nie jest to dobry wybór. – biomiker

36

type byłaby opcja zalecana do obsługi warunki/kontroli, jak w odpowiedzi Yuushi.

W Twoim konkretnym przypadku, można również użyć parametru choices jeśli górna granica jest również znany:

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

Wyobrażam sobie, że byłoby to dość nieefektywne, ponieważ generowałbyś zakres, a następnie przez niego przechodziłeś, sprawdzając poprawność danych wejściowych. Szybkie 'if' jest znacznie szybsze. – TravisThomas

+2

@ trav1th Rzeczywiście może być, ale jest to przykład użycia z dokumentów. Ponadto, w mojej odpowiedzi powiedziałem, że odpowiedź Yuushiego jest tą, na którą należy odpowiedzieć. Dobrze podać opcje. A w przypadku argparse, dzieje się to raz na wykonanie, używa generatora ('xrange') i nie wymaga dodatkowego kodu. Ten kompromis jest dostępny. Do każdego należy decyzja, którą drogą wybrać. – aneroid

+9

Aby być bardziej zrozumiałym co do punktu jgritty na temat ben autorskiej odpowiedzi, choice = xrange (0,1000) spowoduje, że cała lista liczb całkowitych od 1 do 999 włącznie zostanie zapisana na konsoli za każdym razem gdy użyjesz --help lub jeśli nieważny argument jest zapewniony. W większości przypadków nie jest to dobry wybór. – biomiker

2

Prostsza alternatywę, zwłaszcza jeśli instacji argparse.ArgumentParser, jest inicjowanie walidacji od wewnątrz metody parse_args .

Wewnątrz takiej podklasy:

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 

Technika ta nie może być cool, jak zwyczaj wymagalne, ale spełnia swoje zadanie.


O 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.


kredytowe: answer by jonatan

Powiązane problemy