2016-03-22 28 views
27

Sto provando a scrivere uno script che accetta più origini di input e fa qualcosa a ciascuno. Qualcosa di simileUtilizzo della stessa opzione più volte in Argparse di Python

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

Ma io non riesco a capire come fare questo usando argparse, sembra che è impostato in modo che ogni bandiera opzione può essere utilizzato solo una volta. So come associare più argomenti con una singola opzione (nargs = '*' o nargs = '+'), ma che comunque non mi permetterà di usare il flag -i più volte. Come faccio a realizzare questo.

Giusto per essere chiari, quello che mi piacerebbe alla fine è un elenco di liste di stringhe. Così

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

Quindi, perché non associare più argomenti di input source con quella singola opzione? – TigerhawkT3

+0

Poiché ciascuna delle molteplici origini di input deve disporre anche di più argomenti di stringa. Mi piacerebbe dover usare il flag -i per ciascuno degli input e ogni input conterrà tutte le stringhe tra i successivi flag -i. Voglio che funzioni come ffmpeg dove specifichi input con -i –

risposta

32

Ecco un parser che gestisce un 2 argomento ripetuto opzionale - con i nomi definiti nel metavar:.

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']]) 

Questo fa non gestire il caso 2 or 3 argument (sebbene abbia scritto una patch qualche tempo fa per un bug/problema Python che gestisse un intervallo di questo tipo)

Come definire una definizione argomento separata con nargs=3 e metavar=('url','name','other')?

La tupla metavar può essere utilizzata anche con nargs='+' e nargs='*'; le 2 stringhe vengono utilizzate come [-u A [B ...]] o [-u [A [B ...]]].

+0

Wow, bello! Mi piace come la funzione di guida mostri cosa rappresentano i singoli componenti dell'opzione multiparte. Lo userò! –

11

-i dovrebbe essere configurato per accettare 3 argomenti e di utilizzare l'azione append.

> 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']]) 

Per gestire un valore facoltativo, è possibile provare a utilizzare un tipo personalizzato semplice. In questo caso, l'argomento su -i è una stringa delimitata da una virgola singola, con il numero di divisioni limitato a 2. È necessario elaborare i valori per garantire che siano specificati almeno due valori.

> 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']]) 

Per ulteriori controlli, definire un'azione personalizzata. Questo estende il built-in _AppendAction (utilizzato da 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

Brilliant! Grazie per l'aiuto. –

+2

Questo non * fa * quello che vuoi; Ho perso il fatto che 'inputX_other_var' è facoltativo. – chepner

+0

Sono appena tornato per commentare in quanto tale, la tua strada richiede tutti i vars. È nella direzione giusta però! –