2016-03-22 14 views
27

Ich versuche, ein Skript zu schreiben, das mehrere Eingabequellen akzeptiert und tut etwas für jeden. So etwas wie diesVerwenden Sie die gleiche Option mehrmals in Python Argarse

./my_script.py -i input1_url input1_name input1_other_var -i input2_url input2_name input2_other_var -i input3_url input3_name # notice inputX_other_var is optional 

Aber ich kann nicht ganz herausfinden, wie dies mit argparse zu tun, so scheint es, dass es so einrichten, dass jede Option Flag kann nur einmal verwendet werden. Ich weiß, wie man mehrere Argumente mit einer einzigen Option verbindet (nargs = '*' oder nargs = '+'), aber das lässt mich immer noch nicht das Flag -i mehrfach verwenden. Wie kann ich das erreichen?

Nur um klar zu sein, was ich am Ende möchte, ist eine Liste von Strings. So

[["input1_url", "input1_name", "input1_other"], 
["input2_url", "input2_name", "input2_other"], 
["input3_url", "input3_name"]] 
+0

Warum also nicht die Argumente für mehrere Eingabequellen mit dieser einzelnen Option verknüpfen? – TigerhawkT3

+0

Da jede der mehreren Eingabequellen auch mehrere Zeichenfolgenargumente haben muss. Ich würde gerne die -i-Flag für jeden der Eingänge verwenden, und jeder Eingang würde alle Zeichenfolgen zwischen aufeinander folgenden -i Flags enthalten. Ich möchte, dass es wie ffmpeg funktioniert, wo Sie Eingänge mit -i –

Antwort

32

Hier ist ein Parser, der ein wiederholtes 2 Argument optional Griffe - mit Namen in den metavar definiert:.

parser=argparse.ArgumentParser() 
parser.add_argument('-i','--input',action='append',nargs=2, 
    metavar=('url','name'),help='help:') 

In [295]: parser.print_help() 
usage: ipython2.7 [-h] [-i url name] 

optional arguments: 
    -h, --help   show this help message and exit 
    -i url name, --input url name 
         help: 

In [296]: parser.parse_args('-i one two -i three four'.split()) 
Out[296]: Namespace(input=[['one', 'two'], ['three', 'four']]) 

Dies tut nicht mit dem 2 or 3 argument Fall umgehen (obwohl ich vor einiger Zeit einen Patch für einen Python Fehler geschrieben habe, der einen solchen Bereich behandelt)

Wie wäre es mit einer separaten Argumentdefinition mit nargs=3 und metavar=('url','name','other')?

Das Tupel metavar kann auch mit nargs='+' und nargs='*' verwendet werden; Die 2 Strings werden als [-u A [B ...]] oder [-u [A [B ...]]] verwendet.

+0

Wow schön! Ich liebe, wie die Hilfe-Funktion zeigt, was die einzelnen Komponenten der Multi-Teil-Option darstellen. Ich werde das benutzen! –

11

-i sollte so konfiguriert werden, 3 Argumente zu akzeptieren und die append Aktion zu verwenden.

> p = argparse.ArgumentParser() 
> p.add_argument("-i", nargs=3, action='append') 
_AppendAction(...) 
> p.parse_args("-i a b c -i d e f -i g h i".split()) 
Namespace(i=[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]) 

Um einen optionalen Wert zu verarbeiten, können Sie versuchen, einen einfachen benutzerdefinierten Typ zu verwenden. In diesem Fall ist das Argument -i eine einzelne durch Trennzeichen getrennte Zeichenfolge, wobei die Anzahl der Aufteilungen auf 2 beschränkt ist. Sie müssen die Werte nachbearbeiten, um sicherzustellen, dass mindestens zwei Werte angegeben sind.

> p.add_argument("-i", type=lambda x: x.split(",", 2), action='append') 
> print p.parse_args("-i a,b,c -i d,e -i g,h,i,j".split()) 
Namespace(i=[['a', 'b', 'c'], ['d', 'e'], ['g', 'h', 'i,j']]) 

Für mehr Kontrolle definieren Sie eine benutzerdefinierte Aktion. Dies erstreckt sich die eingebauten in _AppendAction (verwendet von action='append'), but just does some range checking on the number of arguments given to -i`

class TwoOrThree(argparse._AppendAction): 
    def __call__(self, parser, namespace, values, option_string=None): 
     if not (2 <= len(values) <= 3): 
      raise argparse.ArgumentError(self, "%s takes 2 or 3 values, %d given" % (option_string, len(values))) 
     super(TwoOrThree, self).__call__(parser, namespace, values, option_string) 

p.add_argument("-i", nargs='+', action=TwoOrThree) 
+0

angeben Brilliant! Danke für Ihre Hilfe. –

+2

Das tut nicht * ganz * was Sie wollen; Ich habe übersehen, dass "inputX_other_var" optional ist. – chepner

+0

Ich kam gerade zurück, um als solche zu kommentieren, Ihr Weg erfordert alle vars. Es ist jedoch in die richtige Richtung! –

Verwandte Themen