2015-06-19 15 views
7

Próbuję wprowadzić opcjonalny argument dla skryptu, który nie może przyjmować żadnych wartości ani 2 wartości, nic więcej. Czy możesz to zrobić za pomocą argparse?argparse - wymagająca 2 wartości lub żadnej dla opcjonalnego argumentu

# desired output: 
# ./script.py -a --> works 
# ./script.py -a val1 --> error 
# ./script.py -a val1 val2 --> works 


wersja 1 - przyjmuje wartości 0 lub 1:

parser = argparse.ArgumentParser() 
parser.add_argument("-a", "--action", nargs="?", const=True, action="store", help="do some action") 
args = parser.parse_args() 

# output: 
# ./script.py -a --> works 
# ./script.py -a val1 --> works 
# ./script.py -a val1 val2 --> error 


Wersja 2 - Akceptuje dokładnie 2 wartości:

parser = argparse.ArgumentParser() 
parser.add_argument("-a", "--action", nargs=2, action="store", help="do some action") 
args = parser.parse_args() 

# output: 
# ./script.py -a --> error 
# ./script.py -a val1 --> error 
# ./script.py -a val1 val2 --> works 


Jak połączyć te 2 różne wersje, dzięki czemu skrypt akceptuje 0 lub 2 wartości argumentu, ale odrzuca kiedy ma tylko jedną wartość?

Odpowiedz

6

Będziesz musiał zrobić własne sprawdzanie błędów tutaj. Zebrane 0 lub więcej wartości, a odrzucać coś innego niż 0 lub 2:

parser = argparse.ArgumentParser() 
parser.add_argument("-a", "--action", nargs='*', action="store", help="do some action") 
args = parser.parse_args() 

if args.action is not None and len(args.action) not in (0, 2): 
    parser.error('Either give no values for action, or two, not {}.'.format(len(args.action))) 

Zauważ, że args.action jest ustawiony na None gdy nie -a przełącznik użyto:

>>> import argparse 
>>> parser = argparse.ArgumentParser() 
>>> parser.add_argument("-a", "--action", nargs='*', action="store", help="do some action") 
_StoreAction(option_strings=['-a', '--action'], dest='action', nargs='*', const=None, default=None, type=None, choices=None, help='do some action', metavar=None) 
>>> args = parser.parse_args([]) 
>>> args.action is None 
True 
>>> args = parser.parse_args(['-a']) 
>>> args.action 
[] 
+0

tym rozwiązaniem "./script.py" działa tak samo jak "./script.py -a" – xgord

+0

@ xgord: w obu przypadkach nie chciałbyś błędu. Chcesz błędu podczas używania './script.py -a foo' lub' ./script.py -a foo bar baz' i dłużej. –

+0

@xgord: ta kontrola * nie * dotyczy postępowania z przypadkiem './Script.py', dotyczy tylko zgłoszenia błędu przy użyciu opcji' -a', ale z niepoprawną liczbą argumentów. Czego spodziewałeś się zamiast tego w tym przypadku? –

3

Wystarczy sobie, że sprawa się:

parser.add_argument("-a", "--action", nargs='*', action="store", help="do some action") 
args = parser.parse_args() 

if args.action is not None: 
    if len(args.action) not in (0, 2): 
     parser.error('Specify no or two actions') 

    # action was specified but either there were two actions or no action 
else: 
    # action was not specified 

Oczywiście należy zaktualizować tekst pomocy w tym przypadku, dzięki czemu użytkownik ma szansę dowiedzieć się tego przed uruchomieniem do błędu.

+0

z tego rozwiązania „./script.py” działa tak samo jak „./script.py -a” – xgord

+0

Jak tam jest praktyczna różnica między tymi dwoma? – poke

+1

@xgord To naprawdę nie działa tak samo. jeśli użyjesz './script.py', argumentem" args.action "będzie" Brak "; jeśli użyjesz './script.py -a', wtedy' args.action' będzie miało postać '[]'. – poke

-1

Jak o wymaganej argumentu: parser.add_argument("-a", "--action", nargs=2, action="store", help="do some action", required=False)

+1

To nie działa, '-a' bez żadnych wartości powoduje błąd, ponieważ nie jest to dokładnie 2 elementy. 'required = False' to * wartość domyślna * mimo to. –

+1

Opcje ('--like-this lub tego') nie są domyślnie wymagane z argparse. – poke

0

Masz opcję, aby pobrać pojedynczy, opcjonalny ciąg znaków oddzielany przecinkami. Użyjesz niestandardowego typu, aby przekonwertować ten ciąg do listy i sprawdzić, czy ma dokładnie dwie pozycje.

def pair(value): 
    rv = value.split(',') 
    if len(rv) != 2: 
     raise argparse.ArgumentParser() 
    return rv 

parser.add_argument("-a", "--action", nargs='?', 
        type=pair, metavar='val1,val2', 
        help="do some action") 
print parser.parse_args() 

Potem go używać jak

$ ./script.py -a 
Namespace(action=None) 
$ ./script.py -a val1,val2 
Namespace(action=['val1','val2']) 
$ ./script.py -a val1 
usage: tmp.py [-h] [-a [ACTION]] 
script.py: error: argument -a/--action: invalid pair value: 'val1' 
$ ./script.py -a val1,val2,val3 
usage: tmp.py [-h] [-a [ACTION]] 
script.py: error: argument -a/--action: invalid pair value: 'val1,val2,val3' 

Można dostosować definicję pair użyć innego separatora i powrócić coś innego niż listy (krotka, na przykład).

Parametr metavar zapewnia lepszą wskazówkę, że argumentem dla action jest para wartości, a nie tylko jedna.

$ ./script.py -h 
usage: script.py [-h] [-a [val1,val2]] 

optional arguments: 
    -h, --help   show this help message and exit 
    -a [val1,val2], --action [val1,val2] 
         do some action 
Powiązane problemy