2016-03-22 1 views
27

J'essaye d'écrire un script qui accepte plusieurs sources d'entrée et qui fait quelque chose à chacun. Quelque chose comme çaUtiliser la même option plusieurs fois dans Argparse de 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 

Mais je ne peux pas comprendre tout à fait comment le faire en utilisant argparse, il semble qu'il est mis en place afin que chaque drapeau d'option ne peut être utilisée qu'une seule fois. Je sais comment associer plusieurs arguments avec une seule option (nargs = '*' ou nargs = '+'), mais cela ne me permettra pas d'utiliser l'option -i plusieurs fois. Comment puis-je accomplir cela? Juste pour être clair, ce que je voudrais à la fin est une liste de chaînes de caractères. Alors

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

Alors, pourquoi ne pas associer les multiples arguments de source d'entrée à cette seule option? – TigerhawkT3

+0

Parce que chacune des sources d'entrée multiples doivent également avoir plusieurs arguments de chaîne. Je voudrais utiliser l'indicateur -i pour chacune des entrées, et chaque entrée contiendrait toutes les chaînes entre les drapeaux -i successifs. Je veux que cela fonctionne comme ffmpeg où vous spécifiez les entrées avec -i –

Répondre

32

est ici un analyseur qui gère un argument optionnel répété 2 - avec des noms définis dans le 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']]) 

Cela fait. ne gère pas le cas 2 or 3 argument (même si j'ai écrit un correctif il y a un certain temps pour un bogue/problème Python qui gérerait une telle plage)

Que diriez-vous d'une définition d'argument séparée avec nargs=3 et metavar=('url','name','other')?

Le tuple metavar peut également être utilisé avec nargs='+' et nargs='*'; les 2 chaînes sont utilisées comme [-u A [B ...]] ou [-u [A [B ...]]].

+0

Wow sympa! J'aime la façon dont la fonction d'aide montre ce que représentent les composants individuels de l'option multi-pièces. Je vais utiliser ça! –

11

-i doit être configuré pour accepter les 3 arguments et d'utiliser l'action 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']]) 

Pour gérer une valeur facultative, vous pouvez essayer d'utiliser un type personnalisé simple. Dans ce cas, l'argument -i est une seule chaîne délimitée par des virgules, le nombre de divisions étant limité à 2. Vous devez post-traiter les valeurs pour vous assurer qu'au moins deux valeurs sont spécifiées.

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

Pour plus de contrôle, définissez une action personnalisée. Celui-ci étend le haut-_AppendAction (utilisé par 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! Merci de votre aide. –

+2

Cela ne fait pas * tout à fait * ce que vous voulez; J'ai manqué que 'inputX_other_var' est optionnel. – chepner

+0

Je viens juste de commenter en tant que tel, votre chemin exige toutes les vars. C'est dans la bonne direction cependant! –