2015-06-19 3 views
7

Ich versuche, ein optionales Argument für ein Skript, das entweder keine Werte oder 2 Werte, nichts anderes nehmen kann. Kannst du das mit argparse erreichen?argparse - erfordert entweder 2 Werte oder keine für ein optionales Argument

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


Version 1 - akzeptiert 0 oder 1 Werte:

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 


Version 2 - akzeptiert genau 2 Werte:

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 


Wie kombinieren Sie diese 2 verschiedene Versionen, so dass das Skript 0 oder 2 Werte für das Argument akzeptiert, aber ablehnt wenn es nur 1 Wert hat?

Antwort

6

Sie müssen hier Ihre eigenen Fehler überprüfen. Akzeptieren 0 oder mehr Wert, und lehnen alles andere als 0 oder 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))) 

Beachten Sie, dass args.action-None gesetzt wird, wenn kein -a Schalter verwendet:

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

mit dieser Lösung "./script.py" verhält sich genauso wie "./script.py -a" – xgord

+0

@xgord: In beiden Fällen möchten Sie keinen Fehler. Sie möchten einen Fehler, wenn Sie './script.py -a foo' oder' ./script.py -a foo bar baz' und länger verwenden. –

+0

@xgord: Diese Überprüfung ist * nicht * um den Fall './Script.py' zu behandeln, nur um einen Fehler zu erzeugen, wenn' -a' verwendet wurde, aber mit der falschen Anzahl von Argumenten. Was haben Sie in diesem Fall erwartet? –

3

Griff Genau diesem Fall selbst:

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 

Natürlich sollten Sie den Hilfetext in diesem Fall zu aktualisieren, so dass der Benutzer die Möglichkeit hat, dies zu wissen, bevor sie in den Fehler ausgeführt wird.

+0

mit dieser Lösung „./script.py“ wirkt das gleiche wie „./script.py -a“ – xgord

+0

Wie ist es eine praktische Unterschied zwischen den beiden? – poke

+1

@xgord Es verhält sich tatsächlich nicht gleich. Wenn Sie './script.py' verwenden, ist' args.action' 'None'; Wenn Sie './script.py -a' verwenden, wird' args.action' '' [] 'sein. – poke

-1

Wie über das erforderliche Argument: parser.add_argument("-a", "--action", nargs=2, action="store", help="do some action", required=False)

+1

Dies funktioniert nicht, "-a" ohne irgendwelche Werte gibt einen Fehler, weil es nicht genau 2 Elemente ist. 'required = False' ist sowieso * der Standard *. –

+1

Optionale ('--like-this -or-this') sind standardmäßig nicht mit argparse erforderlich. – poke

0

Wählen Sie eine einzelne, optionale, durch Komma getrennte Zeichenfolge. Sie verwenden einen benutzerdefinierten Typ, um diese Zeichenfolge in eine Liste zu konvertieren und sicherzustellen, dass sie genau zwei Elemente enthält.

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

Dann würden Sie es verwenden, wie

$ ./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' 

können Sie die Definition von pair anpassen einen anderen Separator zu verwenden, und etwas anderes als eine Liste zurückzukehren (ein Tupel, zum Beispiel).

Die metavar bietet eine bessere Anzeige, dass das Argument zu action ein Paar Werte ist, anstatt nur eins.

$ ./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 
Verwandte Themen