2017-01-10 4 views
2

я следующие коды:Как передать параметр в классе для Argparse факторинга два очень похожих классов

def main(args): 
    """ 
    Description of main 
    """ 
    print args 


if __name__ == '__main__': 
    class DefaultListAction(argparse.Action): 
     CHOICES = ['ann','netmhcpan','comblib_sidney2008','consensus','smm','smmpmbec','netmhccons'] 
     def __call__(self, parser, namespace, values, option_string=None): 
      if values: 
       for value in values: 
        if value not in self.CHOICES: 
         message = ("invalid choice: {0!r} (choose from {1})" 
           .format(value, 
             ', '.join([repr(action) 
                for action in self.CHOICES]))) 

         raise argparse.ArgumentError(self, message) 
       setattr(namespace, self.dest, values) 

    class DefaultListAction_Frames(argparse.Action): 
     CHOICES = ['R','F','6'] 
     def __call__(self, parser, namespace, values, option_string=None): 
      if values: 
       for value in values: 
        if value not in self.CHOICES: 
         message = ("invalid choice: {0!r} (choose from {1})" 
           .format(value, 
             ', '.join([repr(action) 
                for action in self.CHOICES]))) 

         raise argparse.ArgumentError(self, message) 
       setattr(namespace, self.dest, values) 

    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawTextHelpFormatter) 
    parser.add_argument("-iedb",help="IEDB tools options: ann, comblib_sydney2008, consensus, netmhcpan, smm, smmpmbec, netmhccons", \ 
       action=DefaultListAction, nargs='*', default=[''], \ 
       metavar='iedb_tools') 
    parser.add_argument("-f",help="Frame to translate insert: (F)orward three frames, (R)everse three frames or (6) frames F + B. Default F.", \ 
       action=DefaultListAction_Frames, nargs=1, default=['F'], \ 
       metavar='frames') 
    args = parser.parse_args() 
    main(args) 

В принципе, есть два argparse.ArgumentParser.add_argument(), каждый из которых т принимает один из классов в качестве параметра в action.

Мой вопрос в том, как может факторизовать class DefaultListAction(argparse.Action) и класс DefaultListAction_Frames(argparse.Action), учитывая, что единственные различия между ними - это параметр CHOICES.

И как я могу передать эти CHOICES в качестве параметра в argparse.ArgumentParser.add_argument()

+1

'self.choices' должен содержать параметр' choice', указанный в 'add_argument'. См. '__init__' для класса' Action'. 'action.choices' используется в методе' _check_value' и в форматировании справки.Он не используется ни в каком методе 'Action', но я не знаю причин, почему он не может. – hpaulj

+0

@hpaulj: пример пожалуйста. – neversaint

ответ

2

add_argumentchoices параметр доступен как self.choices. Он не используется ни в одном из существующих подклассов Action, но нет причин, по которым он не должен.

Он будет использоваться синтаксическим анализатором для проверки значений до их передачи в Action.__call__. В этом тесте, который, похоже, не конфликтует с вашим собственным использованием, но я не могу это исключить.

action.choices также используются в форматировании справки, хотя параметр metavar переопределяет это.

class ListAction(argparse.Action): 
    # change self.CHOICES to self.choices 
    def __call__(self, parser, namespace, values, option_string=None): 
     if values: 
      for value in values: 
       if value not in self.choices: 
        message = ("invalid choice: {0!r} (choose from {1})" 
          .format(value, 
            ', '.join([repr(action) 
               for action in self.choices]))) 

        raise argparse.ArgumentError(self, message) 
      setattr(namespace, self.dest, values) 

# should behave just like the -f argument 
parser.add_argument("-g",help="Frame to translate insert: (F)orward three frames, (R)everse three frames or (6) frames F + B. Default F.", \ 
      action=ListAction, nargs=1, default=['F'], \ 
      choices=['R','F','6']) 

помощь позволяя choices как metavar (для целей иллюстрации)

2304:~/mypy$ python stack41562756.py -h 
usage: stack41562756.py [-h] [-iedb [iedb_tools [iedb_tools ...]]] [-f frames] 
         [-g {R,F,6}] 

optional arguments: 
    -h, --help   show this help message and exit 
    -iedb [iedb_tools [iedb_tools ...]] 
         IEDB tools options: ann, comblib_sydney2008, consensus, netmhcpan, smm, smmpmbec, netmhccons 
    -f frames    Frame to translate insert: (F)orward three frames, (R)everse three frames or (6) frames F + B. Default F. 
    -g {R,F,6}   Frame to translate insert: (F)orward three frames, (R)everse three frames or (6) frames F + B. Default F. 

При анализе action.choices используется только в _check_value, который вызывается _get_values.

def _check_value(self, action, value): 
    # converted value must be one of the choices (if specified) 
    if action.choices is not None and value not in action.choices: 
     args = {'value': value, 
       'choices': ', '.join(map(repr, action.choices))} 
     msg = _('invalid choice: %(value)r (choose from %(choices)s)') 
     raise ArgumentError(action, msg % args) 

Off стороны это выглядит, как вы могли бы использовать store действие по умолчанию с choices:

parser.add_argument("-e",help="Frame to translate insert: (F)orward three frames, (R)everse three frames or (6) frames F + B. Default F.", \ 
      nargs=1, default=['F'], choices=['R','F','6']) 

Я не вижу ничего в ваших собственных действий, которые по-другому. Но я не изучал и не тестировал их подробно.

=================

Другой подход заключается только подкласс одного из ваших новых действий:

class DefaultListAction_Frames(DefaultListAction): 
    CHOICES = ['R','F','6','X'] 

Если метод __call__ является вам не нужно повторять это.

Другой подход заключается в использовании заводской функции, чтобы дать каждому DefaultListAction Action свой собственный атрибут CHOICES. FileType - такой класс - он создает пользовательскую функцию type.

Функция type - это еще одно место, где вы можете настроить проверку значений. type предназначен для преобразования и тестирования значений, в то время как пользовательские классы действий наиболее полезны, если вы хотите сохранить значения каким-то особым образом.