17

这就是我想做的:一个看起来像 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'

是否可以使用 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:])

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

4

1 回答 1

37

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

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

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())

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

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

解析参数

D:\tmp>s.py a --opt1
Namespace(opt1=True, opt2=False)

B参数被解析

D:\tmp>s.py b
Namespace(opt3=False, opt4=False)

还有参数:

D:\tmp>s.py b --opt3
Namespace(opt3=True, opt4=False)

在B中运行A参数会导致错误:

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

此外,如果您需要确定使用了哪个子解析器,您可以添加dest=name调用parser.add_subparsers()我认为在文档中没有适当强调):

subparsers = parser.add_subparsers(help='sub-command help', dest='subparser_name')

结果是:

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

如果您需要真正动态地创建参数(例如从昂贵的资源中加载一些参数选项),您可以使用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

然后你可以在 上重新执行另一个解析器argv,但我可以想象很少有问题可以解决这个问题,除非真的有必要,否则我不会推荐它。

于 2015-05-13T14:09:22.410 回答