Как передать словарь в аргумент argparse?
Как сделать так, чтобы argparse принимал произвольное количество (0+) опциональных аргументов вида "ключ-значение" в 1 переменную?
Пример:
my_prog.exe --filter_range 42 --filter_type str --filter_time 12:03
Для такого входа надо получить переменную-словарь {'filter_range': '42', 'filter_type': 'str', 'filter_time': '12:03'}.
Попутно вопросы: 1) можно ли задать диапазон для количества таких фильтров (фильтров может быть только от 0 до 5, например) или возможный список ключей (могут быть только фильтры 'filter_range' и 'filter_type', например); 2) можно ли задать типы/диапазоны для ключа и значения (в примере первое значение может быть только натуральным числом).
Можно каждый аргумент задать отдельно, но тогда для составления словаря надо писать сложную логику: отличать такие фильтры от других аргументов, проверять их значения на None и т.п..
Ответы (2 шт):
Вариант 1, словарь как единый аргумент
Передавать словарь можно например как цельную строку в формате JSON:
import argparse
import json
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--my-dict', type=json.loads)
Использовать так:
args = parser.parse_args(['-d', '{\"key1\":\"value1\"}'])
print(args)
Вариант 2, словарь на ключевых словах
Если хочется использовать синтаксис ключевых слов, как для обычных аргументов, то argparse вам не поможет, т.к он создан для работы с конкретными, заранее определёнными ключевыми словами, и надо выбирать что-то из следующих вариантов:
- Если есть какая-то польза от
argparse, то возможно имеет смысл его применять и расширять, например, используя метод.parse_known_args(). - Можно посмотреть альтернативные библиотеки для обработки консольных аргументов, например click, argh, что-то ещё. Возможно где-то в них уже реализован этот функционал.
- Если нигде нет, а очень хочется именно такой синтаксис, то ничто не мешает написать собственный парсер
:)
Покурил маны и нашёл 3 варианта подходящих (реализация первых двух, примеры для третьего):
Сделать 2 парсера. Первый обрабатывает всё кроме фильтров с помощью
parse_known_args(), остальное обрабатывает второй.В одном парсере добавить 2 группы (нефильтры и фильтры) с помощью
add_argument_group(). Это было бы идеально, но проблема в том, что эти группы позволяют только красиво печатать хелп, а получить аргументы, относящиеся к определённой группе, можно только с помощью незадокументированного_group_actions.Использовать
default=argparse.SUPPRESSпри добавлении аргументов. В таком случае аттрибут не будет добавляться в объект вообще, а не получать значениеNone. Тогда можно проитерироваться по всем необработанным аргументам класса парсера с помощьюvars(),dir()и подобного без проверки значений.