子命令后允许argparse全局标志

时间:2014-04-25 15:04:06

标签: python argparse

我正在使用argparse构建一个带有子命令的命令:

mycommand [GLOBAL FLAGS]子命令[FLAGS]

我希望全局标志能够工作,无论它们是在子命令之前还是之后。有没有一种干净的方法可以做到这一点,不涉及重复代码?

例如:

  parser = argparse.ArgumentParser()
  subparsers = parser.add_subparsers(dest='subparser_name')

  parser.add_argument('--disable')    # This flag...

  sp = subparsers.add_parser('compile')
  sp.add_argument('zones', nargs='*')
  sp.add_argument('--disable')        # Is repeated...

  sp = subparsers.add_parser('launch')
  sp.add_argument('zones', nargs='*')
  sp.add_argument('--disable')        # over and over...

我想为许多旗帜做这件事,所以一遍又一遍地重复自己似乎...... unpythonic。

3 个答案:

答案 0 :(得分:11)

这是parents argparse功能的完美用例:

  

有时,一些解析器共享一组共同的参数。宁   比重复这些参数的定义,一个解析器   与所有共享参数一起传递给parents =参数   可以使用ArgumentParser。

定义基本父ArgumentParser,添加将在子分析符之间共享的参数。然后,通过提供parents关键字参数,添加子分析器并将基本分析器设置为父分析器:

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')

base_subparser = argparse.ArgumentParser(add_help=False)
# define common shared arguments
base_subparser.add_argument('--disable')

sp = subparsers.add_parser('compile', parents=[base_subparser])
# define custom arguments
sp = subparsers.add_parser('launch', parents=[base_subparser])
# define custom arguments

请注意,add_help=False此处有助于避免conflicting help argument出现问题。

另见:Python argparse - Add argument to multiple subparsers

答案 1 :(得分:1)

您要求使用argparse解决方案,但是当您还要求使用Pythonic解决方案时,我会故意使用包docopt提出替代方案:

得到它:

$ pip install docopt

将您的代码写入mycommand文件:

"""
Usage:
    mycommand compile [--disable] <zone>...
    mycommand launch  [--disable] <zone>...

Arguments:
    <zone>  zone name

Options:
  -h --help
  --disable  disable

"""
from docopt import docopt

if __name__ == "__main__":
    args = docopt(__doc__)
    print args

然后从命令行调用它:

基本帮助(无参数):

$ python mycommand
Usage:
    mycommand compile [--disable] <zone>...
    mycommand launch  [--disable] <zone>...

寻求帮助:

$ python mycommand -h
Usage:
    mycommand compile [--disable] <zone>...
    mycommand launch  [--disable] <zone>...

Arguments:
    <zone>  zone name

Options:
  -h --help
  --disable  disable

使用compile子命令:

$ python mycommand compile zoneAlfa zoneBeta
{'--disable': False,
 '<zone>': ['zoneAlfa', 'zoneBeta'],
 'compile': True,
 'launch': False}

添加标志--disable:

$ python mycommand compile --disable zoneAlfa zoneBeta
{'--disable': True,
 '<zone>': ['zoneAlfa', 'zoneBeta'],
 'compile': True,
 'launch': False}

launch子命令也适用:

$ python mycommand launch --disable zoneAlfa zoneBeta
{'--disable': True,
 '<zone>': ['zoneAlfa', 'zoneBeta'],
 'compile': False,
 'launch': True}

我对参数解析器的使用也是以argparse开头的,我讨厌代码的复杂性,这是做某事所需要的。

后来我转向plac,这是将python函数转换为非常有用的控制台命令的非常有效的方法。

尽管如此,我受限于遵循和理解的规则,在许多情况下我并不十分清楚。使用docopt我很感激,我可以按照POSIX的标准规则首先编写文档字符串,然后在我的代码中使用它。如果您关心参数的验证,我会指导您阅读这个伟大的包的样本。

答案 2 :(得分:1)

我在你的例子中看到两个问题:

1)在解析器和子解析器中使用'--disable'。 Nested ArgumentParser 处理重叠dest

2)subsparsers中重复的一组参数。 parents肯定是简化这一点的一种方法。但您可以轻松编写自己的代码:

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')

parser.add_argument('--disable', dest='main_disable')    # This flag...

for name in ['compile', 'launch']:
    sp = subparsers.add_parser(name)
    sp.add_argument('zones', nargs='*')
    sp.add_argument('--disable', dest=name+'_disable')        # Is repeated...