Мне кажется, что в argparse есть небольшое ограничение для sub_parsers, если, скажем, у вас есть набор инструментов, которые могут иметь похожие параметры, которые могут распространяться на разные уровни.Такое может случиться редко, но если вы пишете подключаемый / модульный код, это может произойти.
У меня есть следующий пример.Это надуманно и не очень хорошо объяснено в настоящее время, потому что уже довольно поздно, но здесь это идет:
Usage: tool [-y] {a, b}
a [-x] {create, delete}
create [-x]
delete [-y]
b [-y] {push, pull}
push [-x]
pull [-x]
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-x', action = 'store_true')
parser.add_argument('-y', action = 'store_true')
subparsers = parser.add_subparsers(dest = 'command')
parser_a = subparsers.add_parser('a')
parser_a.add_argument('-x', action = 'store_true')
subparsers_a = parser_a.add_subparsers(dest = 'sub_command')
parser_a_create = subparsers_a.add_parser('create')
parser_a_create.add_argument('-x', action = 'store_true')
parser_a_delete = subparsers_a.add_parser('delete')
parser_a_delete.add_argument('-y', action = 'store_true')
parser_b = subparsers.add_parser('b')
parser_b.add_argument('-y', action = 'store_true')
subparsers_b = parser_b.add_subparsers(dest = 'sub_command')
parser_b_create = subparsers_b.add_parser('push')
parser_b_create.add_argument('-x', action = 'store_true')
parser_b_delete = subparsers_b.add_parser('pull')
parser_b_delete.add_argument('-y', action = 'store_true')
print parser.parse_args(['-x', 'a', 'create'])
print parser.parse_args(['a', 'create', '-x'])
print parser.parse_args(['b', '-y', 'pull', '-y'])
print parser.parse_args(['-x', 'b', '-y', 'push', '-x'])
Вывод
Namespace(command='a', sub_command='create', x=True, y=False)
Namespace(command='a', sub_command='create', x=True, y=False)
Namespace(command='b', sub_command='pull', x=False, y=True)
Namespace(command='b', sub_command='push', x=True, y=True)
Как видите,трудно определить, где в цепочке был задан каждый аргумент.Вы можете решить эту проблему, изменив имя для каждой переменной.Например, вы можете установить для dest значение «x», «a_x», «a_create_x», «b_push_x» и т. Д., Но это будет болезненно и трудно отделить.
Альтернативой будетостановить ArgumentParser, как только он достигнет подкоманды, и передать оставшиеся аргументы другому, независимому парсеру, чтобы он мог генерировать отдельные объекты.Вы можете попытаться добиться этого, используя parse_known_args () и не определяя аргументы для каждой подкоманды.Тем не менее, это было бы нехорошо, потому что любые непроверенные аргументы, которые были до этого, все равно будут присутствовать и могут запутать программу.
Мне кажется, что это немного дешево, но полезный обходной путь - это argparse интерпретировать следующие аргументы как строкив списке.Это можно сделать, установив для префикса нулевой терминатор «\ 0» (или какой-либо другой «сложный в использовании» символ) - если префикс пуст, код выдаст ошибку, по крайней мере, в Python 2.7.3.
Пример:
parser = ArgumentParser()
parser.add_argument('-x', action = 'store_true')
parser.add_argument('-y', action = 'store_true')
subparsers = parser.add_subparsers(dest = 'command')
parser_a = subparsers.add_parser('a' prefix_chars = '\0')
parser_a.add_argument('args', type = str, nargs = '*')
print parser.parse_args(['-xy', 'a', '-y', '12'])
Вывод:
Namespace(args=['-y', '12'], command='a', x=True, y=True)
Обратите внимание, что он не использует второй параметр -y
.Затем вы можете передать результат 'args' другому ArgumentParser.
Недостатки:
- Справка может быть обработана неправильно.С этим
- придется искать обходные пути, которые трудно отследить и требуют дополнительных усилий для обеспечения правильной цепочки сообщений об ошибках.
- Немного больше накладных расходов, связанных снесколько ArgumentParsers.
Если у кого-то есть дополнительные материалы по этому вопросу, пожалуйста, сообщите мне.