Python argparse,根据父参数值提供不同的参数

Nar*_*the 8 python dynamic argparse subparsers

这是我想要做的:一个看起来像git命令行为的命令.无论是键入git commit还是git checkout,都没有相同的选项.但在我的情况下,我想提供基于参数值(文件名)的不同参数,如下所示:

>cmd file.a -h
usage: cmd filename [-opt1] [-opt2]
positional arguments:
filename         file to process
optional arguments:
-opt1            do something on files of type 'a'
-opt2            do something else on files of type 'a'

>cmd file.b -h
usage: cmd filename [-opt3] [-opt4] 
positional arguments:
filename         file to process
optional arguments:
-opt3            do something on files of type 'b'
-opt4            do something else on files of type 'b'
Run Code Online (Sandbox Code Playgroud)

使用python和argparse可以做这种事情吗?
到目前为止我尝试的是:

parser = argparse.Argument_parser(prog='cmd')
subparsers = parser.add_subparsers()

parser.add_argument('filename', 
                    help="file or sequence to process")

args = parser.parse_args(args=argv[1:])

sub_parser = subparsers.add_parser(args.filename, help="job type")
base, ext = os.path.splitext(args.filename)
if ext == 'a':
    sub_parser.add_argument("-opt1", action='store_true')
    sub_parser.add_argument("-opt2", action='store_true')
elif ext == 'b':
    sub_parser.add_argument("-opt3", action='store_true')
    sub_parser.add_argument("-opt4", action='store_true')

args = parser.parse_args(args=argv[1:])
Run Code Online (Sandbox Code Playgroud)

我不知道我是否应该使用子分析器或子分析器或组,我有点迷失在argparse提供的所有可能性中

Vyk*_*tor 23

当您查看parse_args()实现时,您会注意到它一次解析所有参数(它不yield用于连续生成状态),因此您必须在解析一半参数之前而不是之后准备您的结构.

从文档中的官方示例中,您应该在开始解析之前添加subparser,如下所示:

import argparse

parser = argparse.ArgumentParser(prog='PROG')
subparsers = parser.add_subparsers(help='sub-command help')

# create the parser for the "a" command
parser_a = subparsers.add_parser('a', help='a help')
parser_a.add_argument("--opt1", action='store_true')
parser_a.add_argument("--opt2", action='store_true')

# create the parser for the "b" command
parser_b = subparsers.add_parser('b', help='b help')
parser_b.add_argument("--opt3", action='store_true')
parser_b.add_argument("--opt4", action='store_true')

# parse some argument lists
print(parser.parse_args())
Run Code Online (Sandbox Code Playgroud)

并且输出(在命令行中),帮助很好地打印:

D:\tmp>s.py -h
usage: PROG [-h] {a,b} ...

positional arguments:
  {a,b}       sub-command help
    a         a help
    b         b help

optional arguments:
  -h, --help  show this help message and exit
Run Code Online (Sandbox Code Playgroud)

一个参数解析

D:\tmp>s.py a --opt1
Namespace(opt1=True, opt2=False)
Run Code Online (Sandbox Code Playgroud)

解析B参数

D:\tmp>s.py b
Namespace(opt3=False, opt4=False)
Run Code Online (Sandbox Code Playgroud)

还有args:

D:\tmp>s.py b --opt3
Namespace(opt3=True, opt4=False)
Run Code Online (Sandbox Code Playgroud)

运行一个在辩论中导致的错误:

D:\tmp>s.py b --opt2
usage: PROG [-h] {a,b} ...
PROG: error: unrecognized arguments: --opt2
Run Code Online (Sandbox Code Playgroud)

此外,如果您需要确定使用了哪个subparser,您可以添加dest=nameparser.add_subparsers()call(我认为在文档中没有正确强调):

subparsers = parser.add_subparsers(help='sub-command help', dest='subparser_name')
Run Code Online (Sandbox Code Playgroud)

结果如下:

D:\tmp>s.py b --opt3
Namespace(opt3=True, opt4=False, subparser_name='b')
Run Code Online (Sandbox Code Playgroud)

如果您需要动态创建参数(例如从昂贵的资源加载一些参数选项),您可以使用parse_known_args():

有时,脚本可能只解析一些命令行参数,将剩余的参数传递给另一个脚本或程序.在这些情况下,该parse_known_args()方法可能是有用的.它的工作方式非常类似,parse_args()只是在存在额外参数时不会产生错误.相反,它返回一个包含填充命名空间和剩余参数字符串列表的两项元组.

毕竟,parse_args()只需检查尾随的纪念碑:

def parse_args(self, args=None, namespace=None):
    args, argv = self.parse_known_args(args, namespace)
    if argv:
        msg = _('unrecognized arguments: %s')
        self.error(msg % ' '.join(argv))
    return args
Run Code Online (Sandbox Code Playgroud)

然后你可以重新执行另一个解析器argv,但是我可以想象一些可以解决这个问题的问题,在真正需要之前我不会推荐它.