1

我正在构建一个 CLI,它利用子解析器来处理类似于 git 之类的工具的子命令。我的一些子命令共享通用选项,因此我有一个定义选项的组解析器,每个需要它们的子命令都parents=group_parser用作参数之一。例如:

group_parser = argparse.ArgumentParser()
group_parser.add_argument('-f', '--foo', action='store_true')

command1_parser = subparsers.add_parser('command1', parents=[group_parser])
command2_parser = subparsers.add_parser('command2', parents=[group_parser])

如您所见, command1 和 command2 都继承了 option --foo。我要做的是分别在 command1 和 command2 上更新 foo 的帮助文本。例如,如果我跑步myprog command1 -h,我希望它--foo在我跑步时说出不同的帮助信息myprog command2 -h。问题是直到我这样做之前parse_args()没有为该参数更新的命名空间,所以这样的事情不起作用:

group_parser = argparse.ArgumentParser()
group_parser.add_argument('-f', '--foo', action='store_true')

command1_parser = subparsers.add_parser('command1', parents=[group_parser])
command1.foo['help'] = "foo help for command1"
command2_parser = subparsers.add_parser('command2', parents=[group_parser])
command2.foo['help'] = "foo help for command2"

这是否可以以某种方式向函数外部的参数添加额外的参数add_argument()?唯一的其他解决方案是不使用继承的父级,只为每个子命令单独定义 foo ,但如果有更新参数的方法,那将是理想的。

4

1 回答 1

3

help在创建 Action(参数)之后,有一种方法可以更改(和其他 Action 属性)。但是这个parents机制还有另一个问题——动作是通过引用来复制的。所以即使你可以改变helpfor command1,你最终command2也会改变它 for 。我在尝试更改诸如default.

我将添加一个插图,并且可能是之前讨论的链接。

In [2]: parent = argparse.ArgumentParser(add_help=False)
In [4]: fooObj = parent.add_argument('--foo',default='foo1', help='foo help')

fooObj是对由 this 创建的 Action 的引用add_argument

In [5]: fooObj.default
Out[5]: 'foo1'
In [6]: fooObj.help      # the help parameter        
Out[6]: 'foo help'
In [7]: parent.print_help()
usage: ipython3 [--foo FOO]

optional arguments:
  --foo FOO  foo help

更改帮助属性:

In [8]: fooObj.help = 'new help'
In [9]: parent.print_help()
usage: ipython3 [--foo FOO]

optional arguments:
  --foo FOO  new help

现在制作一个解析器和子解析器

In [10]: parser = argparse.ArgumentParser()
In [11]: sp = parser.add_subparsers()
In [13]: cmd1 = sp.add_parser('cmd1',parents=[parent])
In [14]: cmd2 = sp.add_parser('cmd2',parents=[parent])

In [15]: cmd2.print_help()
usage: ipython3 cmd2 [-h] [--foo FOO]

optional arguments:
  -h, --help  show this help message and exit
  --foo FOO   new help

_actions是为解析器定义的参数列表:

In [16]: cmd1._actions
Out[16]: 
[_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='foo1', type=None, choices=None, help='new help', metavar=None)]

比较 ids 我们可以看到 2d 动作与fooObj. 与 相同cmd2

In [17]: id(cmd1._actions[1])
Out[17]: 2885458060
In [18]: id(fooObj)
Out[18]: 2885458060

改变helpfor也会cmd1改变它cmd2

In [19]: cmd1._actions[1].help = 'cmd1 foo'
In [20]: cmd2.print_help()
usage: ipython3 cmd2 [-h] [--foo FOO]

optional arguments:
  -h, --help  show this help message and exit
  --foo FOO   cmd1 foo
In [21]: fooObj.help
Out[21]: 'cmd1 foo'

这是一个尝试为子解析器提供不同默认值的案例:

argparse - 结合父解析器、子解析器和默认值

最好使用您自己的实用程序函数将公共参数添加到子解析器。这样,每个子解析器都可以拥有自己的 Action 对象副本,而不是共享它们。我认为该parents机制在理论上比在实践中更好。

于 2017-08-21T23:15:32.400 回答