Python argparse重写来自父级的帮助

Python argparse重写来自父级的帮助,python,argparse,subparsers,Python,Argparse,Subparsers,我正在构建一个CLI,它利用子parser执行类似于git等工具的子命令。我的一些子命令共享公共选项,因此我有一个定义选项的组解析器,需要它们的每个子命令都使用parents=group\u parser作为参数之一。例如: group_parser = argparse.ArgumentParser() group_parser.add_argument('-f', '--foo', action='store_true') command1_parser = subparsers.add_

我正在构建一个CLI,它利用子parser执行类似于git等工具的子命令。我的一些子命令共享公共选项,因此我有一个定义选项的组解析器,需要它们的每个子命令都使用
parents=group\u 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都继承了选项
--foo
。我要做的是分别在command1和command2上更新foo的帮助文本。例如,如果我运行
myprogcommand1-h
,我希望它在运行
myprogcommand2-h
时为
--foo
显示不同的帮助消息。问题是,在我执行
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,但如果有一种方法可以更新参数,那将是理想的。

有一种方法可以在创建操作(参数)后更改
帮助(和其他操作属性)。但是使用
家长
机制还有另一个问题-操作是通过引用复制的。因此,即使您可以为
command1
更改
帮助
,最终也会将其更改为
command2
。我在尝试更改属性(如
default
)时遇到过这种情况

我将添加一个说明,可能是以前讨论的链接

In [2]: parent = argparse.ArgumentParser(add_help=False)
In [4]: fooObj = parent.add_argument('--foo',default='foo1', help='foo help')
fooObj
是对该
add\u参数创建的操作的引用

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
\u 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)]
比较ID,我们可以看到2d操作与
fooObj
相同。与
cmd2
相同

In [17]: id(cmd1._actions[1])
Out[17]: 2885458060
In [18]: id(fooObj)
Out[18]: 2885458060
更改
cmd1的
help
也会更改
cmd2的
help

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'
下面是一个尝试为子parser提供不同默认值的案例:


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

有一种方法可以在创建操作(参数)后更改
帮助
(和其他操作属性)。但是使用
家长
机制还有另一个问题-操作是通过引用复制的。因此,即使您可以为
command1
更改
帮助
,最终也会将其更改为
command2
。我在尝试更改属性(如
default
)时遇到过这种情况

我将添加一个说明,可能是以前讨论的链接

In [2]: parent = argparse.ArgumentParser(add_help=False)
In [4]: fooObj = parent.add_argument('--foo',default='foo1', help='foo help')
fooObj
是对该
add\u参数创建的操作的引用

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
\u 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)]
比较ID,我们可以看到2d操作与
fooObj
相同。与
cmd2
相同

In [17]: id(cmd1._actions[1])
Out[17]: 2885458060
In [18]: id(fooObj)
Out[18]: 2885458060
更改
cmd1的
help
也会更改
cmd2的
help

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'
下面是一个尝试为子parser提供不同默认值的案例:


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

这是非常有用的信息,感谢其他讨论的链接。这清楚地回答了这个问题,并为各种解决方案提供了许多有用的信息。在命令完全相同的情况下,父命令似乎仍然有用,例如,debug和其他一些选项对于每个子命令在各个方面都完全相同。对于共享相同名称但使用方式略有不同的参数(因此需要不同的帮助命令),我只需将它们拆分,并为每一行创建一个单独的
add_parser
。这是非常有用的信息,感谢其他讨论的链接。这清楚地回答了这个问题,并为各种解决方案提供了许多有用的信息。在命令完全相同的情况下,父命令似乎仍然有用,例如,debug和其他一些选项对于每个子命令在各个方面都完全相同。对于共享相同名称但使用方式略有不同的参数(因此需要不同的帮助命令),我只需将它们拆分,并为每个参数分别创建一行
add\u parser