Ответ 1
Соответствующая ошибка Python Проблема 15112.
argparse: nargs='*'
аргумент positional не принимает никаких элементов, если ему предшествует опция и другой позиционный
Когда argparse анализирует ['1', '2', '--spam', '8', '8', '9']
, он сначала пытается сопоставить ['1','2']
с максимально возможным количеством позиционных аргументов. С вашими аргументами строка соответствия шаблону AAA*
: 1 аргумент для pos
и foo
, а нулевые аргументы для vars
(помните *
означает ZERO_OR_MORE).
['--spam','8']
обрабатываются вашим аргументом --spam
. Поскольку vars
уже установлен в []
, обрабатывать ['8','9']
нечего.
Изменение программирования на argparse
проверяет случай, когда строки аргументов 0
удовлетворяют шаблону, но все еще optionals
обрабатывается. Затем он отменяет обработку этого аргумента *
.
Возможно, вам удастся обойти это, сначала проанализировав вход с помощью parse_known_args
, а затем обработав remainder
другим вызовите parse_args
.
Чтобы иметь полную свободу в вкрапленных опциях из позиций, в issue 14191, я предлагаю использовать parse_known_args
только с optionals
, а затем parse_args
, который знает только о позициях. Функция parse_intermixed_args
, которую я опубликовал там, может быть реализована в подклассе ArgumentParser
без изменения самого кода argparse.py
.
Вот способ обработки подпараметров. Я принял parse_known_intermixed_args
, упростил его ради представления, а затем сделал его функцией parse_known_args
подкласса Parser. Мне пришлось сделать дополнительный шаг, чтобы избежать рекурсии.
Наконец, я изменил _parser_class
подпарамера Action, поэтому каждый подпараметр использует эту альтернативу parse_known_args
. Альтернативой может быть подкласс _SubParsersAction
, возможно модифицирующий его __call__
.
from argparse import ArgumentParser
def parse_known_intermixed_args(self, args=None, namespace=None):
# self - argparse parser
# simplified from http://bugs.python.org/file30204/test_intermixed.py
parsefn = super(SubParser, self).parse_known_args # avoid recursion
positionals = self._get_positional_actions()
for action in positionals:
# deactivate positionals
action.save_nargs = action.nargs
action.nargs = 0
namespace, remaining_args = parsefn(args, namespace)
for action in positionals:
# remove the empty positional values from namespace
if hasattr(namespace, action.dest):
delattr(namespace, action.dest)
for action in positionals:
action.nargs = action.save_nargs
# parse positionals
namespace, extras = parsefn(remaining_args, namespace)
return namespace, extras
class SubParser(ArgumentParser):
parse_known_args = parse_known_intermixed_args
parser = ArgumentParser()
parser.add_argument('foo')
sp = parser.add_subparsers(dest='cmd')
sp._parser_class = SubParser # use different parser class for subparsers
spp1 = sp.add_parser('cmd1')
spp1.add_argument('-x')
spp1.add_argument('bar')
spp1.add_argument('vars',nargs='*')
print parser.parse_args('foo cmd1 bar -x one 8 9'.split())
# Namespace(bar='bar', cmd='cmd1', foo='foo', vars=['8', '9'], x='one')