Имея что-то вроде этого:
>>> import argparse
>>> ap = argparse.ArgumentParser()
>>> ap.add_argument('-e', '--env', action='append', nargs=2, metavar=('NAME', 'VALUE'), dest='extra_env', help='set some env var to given value')
_AppendAction(option_strings=['-e', '--env'], dest='extra_env', nargs=2, const=None, default=None, type=None, choices=None, help='set some env var to given value', metavar=('NAME', 'VALUE'))
это вроде работает:
>>> ap.parse_args(['-e', 'SOMEENVVAR', 'SOMEVAL', '--env', 'OTHERENVVAR', 'OTHERVAL'])
Namespace(extra_env=[['SOMEENVVAR', 'SOMEVAL'], ['OTHERENVVAR', 'OTHERVAL']])
но мне было интересно, как мгновенно преобразовать это в диктовку? Теперь мне нужно сделать это в постобработке:
>>> args = ap.parse_args(['-e', 'SOMEENVVAR', 'SOMEVAL', '--env', 'OTHERENVVAR', 'OTHERVAL'])
>>> dict(args.extra_env)
{'SOMEENVVAR': 'SOMEVAL', 'OTHERENVVAR': 'OTHERVAL'}
Я хотел использовать для этого аргумент type, но кажется, что комбинация action=append и nargs=2 его нарушает; функция, переданная в type, вызывается для каждого аргумента в nargs индивидуально:
>>> ap.add_argument('-e', '--env', action='append', nargs=2, metavar=('NAME', 'VALUE'), dest='extra_env', help='set some env var to given value', type=lambda x: print(f'called lambda for >{x}<'))
_AppendAction(option_strings=['-e', '--env'], dest='extra_env', nargs=2, const=None, default=None, type=<function <lambda> at 0x7f904df518c8>, choices=None, help='set some env var to given value', metavar=('NAME', 'VALUE'))
>>> ap.parse_known_args(['-e', 'SOMEENVVAR','SOMEVAL', '--env', 'OTHERENVVAR','OTHERVAL'])
called lambda for >SOMEENVVAR<
called lambda for >SOMEVAL<
called lambda for >OTHERENVVAR<
called lambda for >OTHERVAL<
(Namespace(extra_env=[[None, None], [None, None]]), [])
@jonrsharpe уже проверил это - см. обновленный вопрос
Хорошо, тогда мы мало что можем добавить!
type получает отдельную строку, а не все строки, указанные в nargs. Пользовательский подкласс action мог бы выполнить эту работу. Но, учитывая, насколько прост этап синтаксического анализа поста, необходим ли он?






Аргумент type передается каждому входу перед применением действия. Вместо этого вы можете передать настраиваемое действие, которое создаст словарь из ваших пар значений.
class DictAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
args_dict = getattr(namespace, self.dest, None) or {}
args_dict.update(dict([values]))
setattr(namespace, self.dest, args_dict)
ap.add_argument(
'-e', '--env',
action=DictAction,
nargs=2,
metavar=('NAME', 'VALUE'),
dest='extra_env',
help='set some env var to given value',
)
Вот результат:
ap.parse_args(['-e', 'SOMEENVVAR', 'SOMEVAL', '--env', 'OTHERENVVAR', 'OTHERVAL'])
# returns:
Namespace(extra_env = {'SOMEENVVAR': 'SOMEVAL', 'OTHERENVVAR': 'OTHERVAL'})
Ниндзя отредактировал, убрав аргумент type.
Если вы действительно посмотрите, с помощью чего вызывается
type, должно быть ясно, что у вас есть лучший подход, который вы, вероятно, получите.