Это работает:
import argparse
class MultichoiceArgumentParser(argparse.ArgumentParser):
def _get_values(self, action, arg_strings):
if isinstance(action.nargs, int):
value = [self._get_value(action, v) for v in arg_strings]
for i, v in enumerate(value):
self._check_value(action, v, arg_num=i)
return value
else:
return super()._get_values(action, arg_strings)
def _check_value(self, action, value, arg_num=None):
# converted value must be one of the choices (if specified)
if action.choices is not None:
choices = action.choices
if isinstance(action, MultichoiceAction):
choices = choices[arg_num]
if value not in choices:
args = {'value': value,
'choices': ', '.join(map(repr, choices))}
msg = argparse._('invalid choice: %(value)r (choose from %(choices)s)')
raise argparse.ArgumentError(action, msg % args)
class MultichoiceAction(argparse._StoreAction):
pass
class MultichoiceFormatter(argparse.HelpFormatter):
def _metavar_formatter(self, action, default_metavar):
if action.choices is not None and isinstance(action, MultichoiceAction):
result = []
for choices in action.choices:
choice_strs = [str(choice) for choice in choices]
result.append('{%s}' % ','.join(choice_strs))
result = tuple(result)
return lambda x: result
else:
return super()._metavar_formatter(action, default_metavar)
Чтобы использовать его:
parser = MultichoiceArgumentParser(formatter_class=MultichoiceFormatter)
parser.add_argument("-a", choices=["ABC", "XYZ"], nargs=2, action=MultichoiceAction)
print(parser.parse_args())
При использовании:
$ python d2.py -h
usage: d2.py [-h] [-a {A,B,C} {X,Y,Z}]
optional arguments:
-h, --help show this help message and exit
-a {A,B,C} {X,Y,Z}
$ python d2.py -a A X
Namespace(a=['A', 'X'])
$ python d2.py -a C Y
Namespace(a=['C', 'Y'])
$ python d2.py -a B Z
Namespace(a=['B', 'Z'])
$ python d2.py -a B B
usage: d2.py [-h] [-a {A,B,C} {X,Y,Z}]
d2.py: error: argument -a: invalid choice: 'B' (choose from 'X', 'Y', 'Z')
$ python d2.py -a X X
usage: d2.py [-h] [-a {A,B,C} {X,Y,Z}]
d2.py: error: argument -a: invalid choice: 'X' (choose from 'A', 'B', 'C')
$ python d2.py -a a b
usage: d2.py [-h] [-a {A,B,C} {X,Y,Z}]
d2.py: error: argument -a: invalid choice: 'a' (choose from 'A', 'B', 'C')
Как показано выше, вы просто должны использовать MultichoiceArgumentParser
с MultichoiceFormatter
как аргумент formatter_class
. Чтобы сделать аргумент с несколькими различными аргументами выбора, choice
должен быть последовательностью последовательностей, такой же длины, как nargs
, а action
должен быть MultichoiceAction
. Это действует так же, как store
, поэтому для других видов поведения потребуется больше подкласса.
Я предлагаю вам использовать docopt (http://docopt.org/), чтобы вы могли просто написать строку использования и сделать это с ней. –
В прошлый раз, когда я смотрел на docopt, он казался мне опрятным, но не таким мощным, как более общий подход, основанный на основе argparse. –
Спасибо за предложения. В итоге я упростил параметры ввода и аргументы программы, тем не менее, прибегая к модулю 'docopt'. Однако я хотел бы увидеть реализацию с использованием модуля 'argparse', если это возможно. – dfernan