尽管我下面提到了bug问题,但你使用的resolve
方法是一个可能的方法。这不适合新手或需要遵循公共API的人。
parser
有一个Action(参数)对象列表(由add_argument
创建)。
使用您的第二个解析器定义,它的_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
的问题感到好奇(请参见评论)。
我创建了一个解析器,然后将其用作另一个解析器的父级(不需要使用子解析器机制)。然后我从一个解析器中删除了一个参数,并查看了另一个解析器中的更改。
创建一个具有一个参数的父解析器:
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)]
请注意,两个解析器的第二个操作是相同的(相同的 id)。
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
代码删除了
--foo
操作中的冲突的
option_strings
,然后将其从
p1._actions
列表中删除。但是更改
p1
引用的
option_strings
也会同时更改
p
引用。
argparse
使用了几种区分
positionals
和
optionals
的方法,但在解析时最常用的方法是查看
option_strings
属性是否为空。通过清空此属性,
resolve
实际上将一个
optional
变成了一个
positional
。
糟糕,我的记忆不如应该的好。:)一年前我回答了一个涉及
parents
和
resolve
的类似问题。
https://dev59.com/woPba4cB1Zd3GeqPrFoD#25821043argparse conflict resolver for options in subcommands turns keyword argument into positional argument
arg1
? - jonrsharpe