Ответ 1
Несмотря на ошибку, о которой я упоминал ниже, использование resolve
предполагает возможный метод. Это не для новичков или тех, кто должен придерживаться публичного API.
parser
имеет список объектов Action (аргумент) (созданных add_argument
).
Используя определение 2-го парсера, его список _actions
:
In [22]: parser._actions
Out[22]:
[_HelpAction(option_strings=['-h', '--help'], dest='help'...),
_StoreAction(option_strings=['--arg2'], dest='arg2', nargs=None,
const=None, default=None, type=None, choices=None,
help='A second one', metavar=None),
_StoreAction(option_strings=['--arg1'], dest='arg1', nargs=None,
const=None, default=None, type=None, choices=None,
help='New number 1', metavar=None)]
Когда вы добавляете конфликтующий с resolve
, он удаляет существующее действие, которое конфликтует. Подробнее см. Метод _handle_conflict_resolve
. Но я могу обмануть его в удалении действия без добавления нового.
In [23]: parser._handle_conflict_resolve(None, [('--arg1',parser._actions[2])])
Посмотрите _actions
и подтвердите, что --arg1
ушел.
In [24]: parser._actions
Out[24]:
[_HelpAction(option_strings=['-h', '--help'], dest='help',....),
_StoreAction(option_strings=['--arg2'], dest='arg2', nargs=None,...)]
In [25]: parser.print_help()
usage: ipython3 [-h] [--arg2 ARG2]
optional arguments:
-h, --help show this help message and exit
--arg2 ARG2 A second one
resolve
просто обрабатывает optionals
, где конфликтуют строки флагов. И сначала удаляет конфликтующие флаги, удаляя противоречивые действия только в том случае, если флаги не остаются. Поэтому будьте особенно внимательны, если у вас есть как короткие, так и длинные варианты.
И это не относится к случаю с позициями. У них нет флагов, и они могут делиться параметрами dest
. (хотя в результате будет отображаться только один, если они не являются добавочными действиями).
In [27]: foo1 = parser.add_argument('foo',help='foo 1 positional')
In [28]: foo2 = parser.add_argument('foo',help='foo 2 positional')
In [29]: parser.print_help()
usage: ipython3 [-h] [--arg2 ARG2] foo foo
positional arguments:
foo foo 1 positional
foo foo 2 positional
...
Играя немного больше, похоже, что я могу удалить один из этих новых позиций:
In [33]: parser._actions[-1]
Out[33]: _StoreAction(option_strings=[], dest='foo',... help='foo 2 positional', metavar=None)
In [35]: foo2=parser._actions[-1]
In [36]: foo2.container._remove_action(foo2)
In [39]: parser.print_help()
usage: ipython3 [-h] [--arg2 ARG2] foo
positional arguments:
foo foo 1 positional
....
Если бы я выбрал _actions[-2]
, я бы удалил первый foo
. Если я присвою значение, которое add_argument
вернется к переменной, например. foo1
, я могу использовать это вместо поиска значения в списке parser._actions
. Может быть полезно запустить образец анализатора в оболочке (я использую IPython) и посмотреть на эти объекты.
Опять же, это, похоже, работает на простом примере, но для тщательного тестирования необходимо использовать его с чем-то более сложным (или для производства).
Тема была поднята на ошибках/проблемах Python пару лет назад:
http://bugs.python.org/issue19462 Add remove_argument() method to argparse.ArgumentParser
Я обсудил трудности полного удаления и предложил некоторые альтернативы. argparse.SUPPRESS
может использоваться для скрытия подсказок. optionals
можно игнорировать, если они не требуются. positionals
сложнее, хотя я предложил настроить их атрибуты (nargs
и default
). Но это было какое-то время, поэтому мне нужно просмотреть эти сообщения.
=============================
Мне было интересно узнать о проблеме @2rs2ts
(см. комментарий).
Я сделал синтаксический анализатор, а затем использовал его как родительский для другого синтаксического анализатора (нет необходимости использовать механизм subparser). Затем я удалил аргумент из одного парсера и посмотрел на изменения в другом парсере.
Сделать родительский синтаксический анализатор с одним аргументом:
In [59]: p=argparse.ArgumentParser()
In [60]: p.add_argument('--foo')
Out[60]: _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
Сделайте еще один с parents
:
In [61]: p1=argparse.ArgumentParser(parents=[p],add_help=False)
In [62]: p1._actions
Out[62]:
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
_StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]
Обратите внимание, что второе действие одинаково для обоих синтаксических анализаторов (тот же идентификатор). parents
просто скопировал ссылку на исходное --foo
действие, оно не сделало копию.
In [63]: id(p._actions[1])
Out[63]: 3000108652
In [64]: id(p1._actions[1])
Out[64]: 3000108652
Теперь удалите '-foo' из одного парсера, используя трюк, который я разработал раньше:
In [65]: p1._handle_conflict_resolve(None,[('--foo',p1._actions[1])])
In [66]: p1._actions
Out[66]: [_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None)]
'- foo' отсутствует в списке p1
, но все еще присутствует в списке p
. Но option_strings
теперь пуст.
In [67]: p._actions
Out[67]:
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
_StoreAction(option_strings=[], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]
Код resolve
удалил конфликтующий option_strings
из действия --foo
, а затем удалил его из списка p1._actions
. Но изменение option_strings
для ссылки p1
также изменило ссылку p
.
argparse
использует несколько способов отличить positionals
от optionals
, но тот, который чаще всего используется при разборе, заключается в том, что атрибут option_strings
пуст или нет. Путем опорожнения этого атрибута resolve
эффективно превратил optional
в positional
.
Упс, моя память не то, что должно быть.:) Год назад я ответил на аналогичный вопрос с участием parents
и resolve
fooobar.com/questions/548037/...
argparse conflict resolver for options in subcommands turns keyword argument into positional argument