【问题标题】:Python argparse override help from parentPython argparse 覆盖来自父级的帮助
【发布时间】:2018-01-30 02:13:14
【问题描述】:

我正在构建一个 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 都继承了选项--foo。我要做的是分别在 command1 和 command2 上更新 foo 的帮助文本。例如,如果我运行myprog command1 -h,我希望它在运行myprog command2 -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,但如果有更新参数的方法,那将是理想的。

【问题讨论】:

    标签: python argparse subparsers


    【解决方案1】:

    有一种方法可以在创建 Action(参数)后更改 help(和其他 Action 属性)。但是使用parents 机制还有另一个问题 - 操作是通过引用复制的。因此,即使您可以将help 更改为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_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
    

    help 更改为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 - Combining parent parser, subparsers and default values

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

    【讨论】:

    • 这是非常有用的信息,并感谢其他讨论的链接。这清楚地回答了这个问题,并为我提供了许多有关各种解决方案的有用信息。在命令字面上相同的情况下,父母似乎仍然有用,例如 --debug 和一些其他选项在每个子命令的各个方面都完全相同。对于名称相同但使用略有不同的 args(因此需要不同的帮助命令),我只是将它们分开并为每个单独的 add_parser 行。
    猜你喜欢
    • 2012-08-17
    • 2022-01-04
    • 2016-02-27
    • 2011-04-11
    • 2019-12-25
    • 2020-12-13
    • 2011-06-30
    • 1970-01-01
    • 2016-03-24
    相关资源
    最近更新 更多