J'essaie d'écrire un script qui accepte plusieurs sources d'entrée et fait quelque chose pour chacune d'elles. Quelque chose comme ça
./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 n'arrive pas à comprendre comment faire cela en utilisant argparse
. Il semble que son paramétrage soit tel que chaque option ne puisse être utilisée qu'une seule fois. Je sais comment associer plusieurs arguments à une seule option (nargs='*'
ou nargs='+'
), mais cela ne me permet toujours pas d’utiliser le -i
drapeau plusieurs fois. Comment puis-je accomplir cela?
Pour être clair, ce que je voudrais à la fin est une liste de listes de chaînes. Alors
[["input1_url", "input1_name", "input1_other"],
["input2_url", "input2_name", "input2_other"],
["input3_url", "input3_name"]]
Voici un analyseur qui gère 2 arguments répétés facultatifs - 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 ne gère pas le cas 2 or 3 argument
(Bien que j’ai écrit un correctif il y a quelque 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 ...]]]
.
-i
Doit être configuré pour accepter 3 arguments et 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 utiliser un type personnalisé simple. Dans ce cas, l'argument de -i
Est une chaîne unique délimitée par des virgules, avec un nombre de divisions 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 _AppendAction
Intégré (utilisé par action='append'
), Mais vérifie simplement l'intervalle de valeurs sur le nombre d'arguments donnés à -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)
C'est simple il suffit d'ajouter les deux action='append'
et nargs='*'
(ou '+'
).
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', action='append', nargs='+')
args = parser.parse_args()
Ensuite, lorsque vous l'exécutez, vous obtenez
In [32]: run test.py -i input1_url input1_name input1_other_var -i input2_url i
...: nput2_name input2_other_var -i input3_url input3_name
In [33]: args.i
Out[33]:
[['input1_url', 'input1_name', 'input1_other_var'],
['input2_url', 'input2_name', 'input2_other_var'],
['input3_url', 'input3_name']]