2015-05-13 46 views
5

这里是我想要做的: 一个看起来像git命令行为的命令。无论您是输入git commit还是git checkout,都无法获得相同的选项。 但在我的情况,我想提供基于一个参数值(文件名)这样的不同的参数:Python argparse,基于父参数值提供不同的参数

>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:]) 

我不知道我是否应该使用subparsers或儿童解析器或群体,我有点失去了通过argparse

+0

根据您想要看到的行为,听起来好像是一个子分析器是您想要去的方式。 –

回答

14
提供的所有可能性

当您看一看parse_args() implementation时,您会注意到它会一次解析所有参数(它不会使用yield来持续生成状态),因此您必须先准备好结构,而不要在解析半数参数之后做好准备。

Taking from official example in the docs你应该开始解析这样的前添加子分析器(S):

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 

A自变量解析

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

参数与ARGS解析

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

另外:

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

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

导致错误运行参数


此外,如果你需要identify which subparser使用您可以添加到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()

Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the parse_known_args() method can be useful. It works much like parse_args() except that it does not produce an error when extra arguments are present. Instead, it returns a two item tuple containing the populated namespace and the list of remaining argument strings.

毕竟,parse_args()只检查后aruments:

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上重新执行另一个解析器,但我可以想象出几个可以解决的问题,我不会推荐它,直到真的需要

+0

真棒回答。享受你的新徽章。 –

+0

重新读一遍。在这里发现仍然层层的迷人:) –