【问题标题】:argparse - Modify the 'required' state of a subcommand's parent argumentsargparse - 修改子命令的父参数的“必需”状态
【发布时间】:2020-10-03 05:05:15
【问题描述】:

我正在尝试在 Python 中构建一个 CLI,并且我有一个参数 (--arg),我想在多个子命令(req 和 opt)中重复使用它。

但是一个子命令 (req) 必须需要 --arg 而另一个 (opt) 不需要。我如何解决这个问题而不必对同一论点制作两个版本?

import argparse
arg_1 = argparse.ArgumentParser(add_help=False)
arg_1.add_argument('-a', '--arg', required=True,
                    help='reusable argument')

parser = argparse.ArgumentParser()
subp = parser.add_subparsers()

cmd_require = subp.add_parser('req', parents=[arg_1],
                                help='this subcommand requires --arg')  
cmd_optional = subp.add_parser('opt', parents=[arg_1],
                                help='this subcommand doesn\'t require --arg')  

【问题讨论】:

    标签: python arguments command-line-interface argparse


    【解决方案1】:

    我不知道有任何“本机”argparse 功能可以做到这一点。不过,我想了 2 种不同的方法来解决您的问题。

    在单独的函数中验证 args - 有时 CLI 应用程序会变得复杂,通过添加验证器函数,您可以“完成”您希望缺少的 argparse 功能。

    import argparse
    arg_1 = argparse.ArgumentParser(add_help=False)
    arg_1.add_argument('-a', '--arg', required=False,
                        help='reusable argument')
    
    parser = argparse.ArgumentParser()
    subp = parser.add_subparsers(dest='sub_parser')
    
    cmd_require = subp.add_parser('req', parents=[arg_1],
                                    help='this subcommand requires --arg')  
    cmd_optional = subp.add_parser('opt', parents=[arg_1],
                                    help='this subcommand doesn\'t require --arg') 
    
    def validate_args(args):
        print(args)
        if args.sub_parser == 'req' and not args.arg:
            print("Invalid usage! using 'req' requires 'arg'")
            exit(1)
    
    if __name__ == '__main__':
        args = parser.parse_args()
        validate_args(args)
    
    

    注意:

    1. 我使用dest 作为子解析器,以便以后识别所选的 子解析器。
    2. 使用 argparse,如果未传递可选参数,则为“无”

    “准备好的论据” - 尽管 argparse 不支持 argument 对象 - 您可以通过解压缩 dict 和元组 (*args, **kwargs) 来“准备”参数

    import argparse
    arg_name = ('-a', '--arg')
    arg_dict = {'help': 'reusable argument'}
    parser = argparse.ArgumentParser()
    subp = parser.add_subparsers()
    
    cmd_require = subp.add_parser('req',
                                    help='this subcommand requires --arg')  
    cmd_optional = subp.add_parser('opt',
                                    help='this subcommand doesn\'t require --arg') 
    
    cmd_optional.add_argument(*arg_name, **arg_dict, required=False)
    cmd_require.add_argument(*arg_name, **arg_dict, required=True)
    
    if __name__ == '__main__':
        args = parser.parse_args()
        validate_args(args)
    

    我更喜欢第一种方法。

    希望你觉得有用

    【讨论】:

      【解决方案2】:
      import argparse
      arg_1 = argparse.ArgumentParser(add_help=False)
      foobar = arg_1.add_argument('-a', '--arg', required=True,
                          help='reusable argument')
      

      arg_1 是一个 parser 对象。当您使用add_argument 命令时,它会创建一个Action 对象并将其添加到args_1._actions 列表中。我刚刚在 foobar 变量中保存了对它的引用。

      parser = argparse.ArgumentParser()
      subp = parser.add_subparsers()
      

      parents 机制将args_1._actions 列表添加到cmd_require._actions 列表中。所以foobar 将出现在两个子解析器中。引用复制,在python中很常见。

      cmd_require = subp.add_parser('req', parents=[arg_1],
                                      help='this subcommand requires --arg')  
      cmd_optional = subp.add_parser('opt', parents=[arg_1],
                                      help='this subcommand doesn\'t require --arg') 
      

      foobar.required=False 将在属性处关闭,但对两个解析器都会这样做。当人们想要分配不同的 default 属性时,我已经看到了这个问题。

      parents 机制只是一个捷径,偶尔有用,但并非总是如此。它没有做任何特别的事情;只是节省了一点打字。还有很多其他方法可以在两个子解析器中定义具有相同标志的动作。

      • 输入两次(太恐怖了!)
      • 复制粘贴
      • 编写实用函数来向子解析器添加参数(请参阅 Larry Wall 的 Three Virtues

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-19
        • 2019-04-04
        • 2012-01-29
        • 2011-07-31
        • 2015-04-15
        • 2014-08-21
        • 2014-10-14
        • 1970-01-01
        相关资源
        最近更新 更多