2010-11-16 14 views
22

J'ai un argument optionnel qui supporte une liste d'arguments elle-même.Python argparse: Existe-t-il un moyen de spécifier une plage dans nargs?

Je veux dire, il devrait soutenir:

  • -f 1 2
  • -f 1 2 3

mais pas:

  • -f 1
  • -f 1 2 3 4

Existe-t-il un moyen de forcer cela dans argparse? Maintenant j'utilise nargs = "*", puis je vérifie la longueur de la liste.

Modifier: Comme demandé, ce dont j'avais besoin est de pouvoir définir une plage de nombre acceptable d'arguments. Je veux dire, en disant (dans l'exemple) 2 ou 3 args est droite, mais pas 1 ou 4 ou tout ce qui est pas dans la gamme 2..3

+0

Je ne comprends pas. Voulez-vous dire que vous voulez être en mesure de soutenir, par exemple, entre un et dix arguments? – katrielalex

+5

Pourriez-vous élaborer davantage sur ce que sont les règles? Vous voulez exiger au moins 2, et au plus 3 valeurs? Doivent-ils être 1-4 ou peuvent-ils être quelque chose? – slf

Répondre

15

Vous pouvez faire cela avec un custom action:

import argparse 

def required_length(nmin,nmax): 
    class RequiredLength(argparse.Action): 
     def __call__(self, parser, args, values, option_string=None): 
      if not nmin<=len(values)<=nmax: 
       msg='argument "{f}" requires between {nmin} and {nmax} arguments'.format(
        f=self.dest,nmin=nmin,nmax=nmax) 
       raise argparse.ArgumentTypeError(msg) 
      setattr(args, self.dest, values) 
    return RequiredLength 

parser=argparse.ArgumentParser(prog='PROG') 
parser.add_argument('-f', nargs='+', action=required_length(2,3)) 

args=parser.parse_args('-f 1 2 3'.split()) 
print(args.f) 
# ['1', '2', '3'] 

try: 
    args=parser.parse_args('-f 1 2 3 4'.split()) 
    print(args) 
except argparse.ArgumentTypeError as err: 
    print(err) 
# argument "f" requires between 2 and 3 arguments 
+1

Voyageur du temps ici. Très bonne réponse! Cependant, vous êtes en train de sous-classer 'argparse.Action' ici ... que se passe-t-il si je veux que mon action soit' append'? Comment puis-je modifier ce code afin que je puisse ajouter plusieurs instances de cet argument, et obtenir également cet effet de plage spécifié? – 2rs2ts

+1

Ah, en fait, fusionner votre code avec [cette réponse] (http://stackoverflow.com/a/5374229/691859) a fait ce que je cherchais. Ne vous occupez pas de moi - à moins que vous pensiez la même chose, dans ce cas, vérifiez cette réponse. – 2rs2ts

+2

Il existe un correctif proposé http://bugs.python.org/issue11354 pour ajouter une option de plage 'nargs', par ex. 'nargs = (2,3)' ou 'nargs = '{2,3}'' (notation '' re'). Cette approche est plus puissante lorsque les autres positions ont des valeurs variables 'nargs'. Sinon, cette approche d'action personnalisée fonctionne correctement. – hpaulj